Elektroda.pl
Elektroda.pl
X

Wyszukiwarki naszych partnerów

Wyszukaj w ofercie 200 tys. produktów TME
Europejski lider sprzedaży techniki i elektroniki.
Proszę, dodaj wyjątek elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

[PHP] FTP, upload plików - błędy

lord_dagoth 29 Gru 2008 14:57 3895 23
  • #1 29 Gru 2008 14:57
    lord_dagoth
    Poziom 25  

    Nie mogę sobie poradzić z prostą funkcją do uploadowania plików na serwer. Za każdym razem wyskakują mi błędy:

    Code:
    Warning: move_uploaded_file(/pliki) [function.move-uploaded-file]: failed to open stream: Permission denied in /home/zima/test1.php on line 17
    
    Warning: move_uploaded_file() [function.move-uploaded-file]: Unable to move '/tmp/phpU5Bvk9' to '/pliki' in /home/zima/test1.php on line 17

    Fragment kodu odpowiedzialny za to:
    Code:
    move_uploaded_file ($_FILES["file"]["tmp_name"],"/pliki")

    Pogooglałem, i we wszystkich postach na wszystkich forach jakie znalazłem były rady dotyczący zmiany uprawnień na folder i plik ze skryptem, i tak zrobiłem. Wszystkim plikom i folderom nadałem chmod'a 777 i nadal ten błąd wyskakuje. Ma ktoś może jakiś pomysł? ;)

  • #3 29 Gru 2008 16:54
    lord_dagoth
    Poziom 25  

    No właśnie już to zrobiłem. Powiedział, że na php on się nie zna, ale ten folder temp ma odpowiedniego chmod'a. Skierował mnie to phpinfo, i w razie czego żebym powiedział co ma dodać. Ale w nim nie za wiele widzę :P Oprócz informacji:
    FTP support enabled

    Jakby to było potrzebne, to: http://krata.bl.pg.gda.pl/zima/info.php

  • Pomocny post
    #5 30 Gru 2008 11:12
    spiderrr0
    Poziom 12  

    O ile się nie mylę to powinno być

    Code:
    /home/zima/pliki/

    A jeśli chcesz mieć pewność, że skrypt jest OK to sprawdz go na Krasnalu albo Webservie
    Zgadzam się że admin, który nie umie skonfigurować serwera to nie admin. :D

  • Pomocny post
    #6 30 Gru 2008 17:34
    bobbyAIR
    Poziom 20  

    To linux i jesli jest w miarę nowy to ustawienia PHP nie wystarczą. Dodatkowo należy zezwolic na upload przez http (czy tam php - nie pamiętam jak to nazwali twórcy) w konfiguracji SELinuxa. Podobnie będzie z funckjami fsockopen w php - to też blokuje SELinux.

    PS: coś takiego jak cechamody (chmod'y - SIC!) nie istnieje.

  • #7 31 Gru 2008 09:11
    lord_dagoth
    Poziom 25  

    Czyli co dokładnie muszę powiedzieć adminowi, żeby sprawdził ustawił?

  • Pomocny post
    #8 31 Gru 2008 09:43
    szwagros
    Poziom 29  

    lord_dagoth napisał:
    Czyli co dokładnie muszę powiedzieć adminowi, żeby sprawdził ustawił?

    Nic.
    Popraw swój skrypt.
    Code:
    move_uploaded_file ($_FILES["file"]["tmp_name"],"/pliki")

    Czy napewno chcesz wrzucać pliki do katalogu '/pliki' ? Jakie ma uprawnienia ten katalog ? Masz dostęp do serwera przez ssh ?

  • #9 31 Gru 2008 09:47
    lord_dagoth
    Poziom 25  

    Tak, do katalogu pliki, wszystkie plik skryptu i folder "pliki" są ustawione na 777

  • Pomocny post
    #10 31 Gru 2008 09:50
    szwagros
    Poziom 29  

    lord_dagoth napisał:
    Tak, do katalogu pliki, wszystkie plik skryptu i folder "pliki" są ustawione na 777

    Nie widzisz różnicy między 'pliki' a '/pliki' ?
    Hint: To pierwsze znaczy to samo, co '/home/zima/pliki'.
    Pozdrawiam sylwestrowo.

  • Pomocny post
    #11 31 Gru 2008 10:28
    BoskiDialer
    Poziom 34  

    Cytat:
    Unable to move '/tmp/phpU5Bvk9' to '/pliki'
    Z tego co wiem, to po odebraniu pliku przenosząc go trzeba zmienić mu nazwę (owe "phpU5Bvk9"). Spróbuj jak już, to takie coś:
    Code:
    move_uploaded_file($_FILES['file']['tmp_name'], '/ścieżka_do_katalogu/pliki/'.$_FILES['file']['name'])

    W przeciwnym przypadku "/pliki" można interpretować jako próba przeniesienia do pliku (nie folderu) o nazwie "pliki" znajdującego się w głónym katalogu "/". Tutaj jest też jawne podanie nazwy, chociaż skrypt może nadać inną nazwę dla pliku (występuje też luka bezpieczeństwa, którą trzeba by załatać).

  • Pomocny post
    #12 31 Gru 2008 11:57
    tzok
    Moderator Samochody

    Tu masz przykładowy skrypt, dodatkowo ma limit wielkości pojedynczego pliku i przyjmuje tylko pliki ZIP (ale to trzeba dopracować, bo IE zwraca inne typy MIME):

    Code:
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>Polskie Multimetry - Upload Plików</title>
    </head>
    <body>
    Przed wysłaniem proszę spakować pliki programem ZIP, max rozmiar pliku to 20MB.<br>
    <form enctype="multipart/form-data" action="upload.php" method="POST">
    <input type="hidden" name="MAX_FILE_SIZE" value="20000000">
    Wybierz plik:
    <input name="uploaded" type="file">
    <input type="submit" value="Wyślij">
    </form>
    <?php
    $plik_nazwa = $_FILES['uploaded']['name'];
    $plik_rozmiar = $_FILES['uploaded']['size'];
    $target = "upload/";
    $target = $target . basename( $_FILES['uploaded']['name']) ;
    $ok=1;

    if(is_uploaded_file($_FILES['uploaded']['tmp_name']))
    {
      //This is our size condition
      if ($uploaded_size > 20000000)
      {
        echo "Twój plik jest za duży, max rozmiar to 20MB.<br>";
        $ok=0;
      }

    //This is our limit file type condition
      if ($uploaded_type!="application/x-zip-compressed"&&$uploaded_type!="application/zip")
      {
        echo "Wysłany plik to: ".$uploaded_type." a dozwolone są tylko pliki ZIP.<br>";
        $ok=0;
      }

    //Here we check that $ok was not set to 0 by an error
      if ($ok==0)
      {
        Echo "Wysyłanie nie powiodło się.";
      }

    //If everything is ok we try to upload it
      else
      {
        if(move_uploaded_file($_FILES['uploaded']['tmp_name'], $target))
        {
          echo "Plik: <strong>$plik_nazwa</strong> o rozmiarze
          <strong>$plik_rozmiar bajtów</strong> został przesłany na serwer!";
        }
        else
        {
          echo "Niestety wystąpił problem z wysyłaniem pliku.";
        }
      }
    }
    ?>
    <hr>
    Pliki oczekujące na przetworzenie:<br>
    <?php
    $sub = ($_GET['dir']);
    $path = 'upload/';
    $path = $path . "$sub";
    $dh = opendir($path);
    $i=1;
    while (($file = readdir($dh)) !== false) {
        if($file != "." && $file != "..") {
            echo "$i. <a href=\"upload/$file\">$file</a><br>";
            $i++;
        }
    }
    closedir($dh);
    ?>

    </body>
    </html>


    Pliki są uploadowane do katalogu /home/<UID>/public_html/upload/ ale dla skryptu php katalogiem bieżącym jest public_html.

  • #13 31 Gru 2008 16:20
    tmassals
    Poziom 11  

    tzok: Kod który zaprezentowałeś pozwala na załadowanie na serwer dowolnego pliku w tym pliku php. Co po załadowaniu takowego może się dziać dalej pozostawiam wyobraźni.

  • Pomocny post
    #14 31 Gru 2008 17:35
    tzok
    Moderator Samochody

    Kod pozwala jedynie na załadowanie pliku ZIP, poza tym można zablokować wykonywanie skryptów z katalogu do którego są uploadowane pliki, można nawet zablokować możliwość odczytu plików w tym katalogu (oczywiście wtedy nie będzie można wyświetlić listy uploadowanych plików).

  • Pomocny post
    #15 31 Gru 2008 20:27
    tmassals
    Poziom 11  

    Sprawdzanie nagłówka nie jest żadnym zabezpieczeniem. Sam zauważyłeś, że przeglądarki wysyłają różne nagłówki. Do spreparowania nagłówka nie potrzeba żadnego specjalnego oprogramowania.
    Kod pozwala wrzucić plik do dowolnego katalogu na dysku do którego ma prawa zapisu serwer www.
    Aby zabezpieczyć kod oprócz tych rzeczy o których napisałeś należałoby:
    -sprawdzić wszystkie dane przesyłane przez użytkownika (w szczególności nazwę pliku z której korzystasz) i usunąć z nich wszelkie niebezpieczne rzeczy (slash'e, backslash'e, wielokropki, procenty itp )
    - katalog do którego zapisywane są dane najlepiej, jeśli to możliwe, umieścić poza katalogiem DocumentRoot i jeśli mają być dostępne przez użytkowników podawać je z wykorzystaniem skryptu pośredniczącego (można wykorzystać readfile)
    - format przesłanego pliku sprawdzać w wiarygodny sposób, np. file lub lepiej odczytując plik przy pomocy narzędzia, które weryfikuje poprawność formatu pliku (w tym przypadku gzip)
    - przypilnować maski dla katalogu do którego trafiają pliki, żeby przypadkiem nie miały prawa wykonywania

  • Pomocny post
    #16 01 Sty 2009 13:53
    tzok
    Moderator Samochody

    ...nie uważasz, że to przesada, jeśli ktoś stosuje takie zabezpieczenia na jakieś domowej stronce? Przecież serwer/parser PHP nie wykona skryptu z pliku innego niż .php
    Poza tym jeśli nie wyświetlasz wysłanych plików, to wysyłający nawet nie wie gdzie trafił plik.
    Skrypt który podałem pochodzi z jakiegoś kursu PHP. Pisząc niewielkie programy na własny użytek czy jakieś proste stronki, nigdy nie zakładam, że ktoś będzie chciał ich używać niezgodnie z przeznaczeniem.

  • #17 01 Sty 2009 16:05
    tmassals
    Poziom 11  

    tzok napisał:
    ...nie uważasz, że to przesada, jeśli ktoś stosuje takie zabezpieczenia na jakieś domowej stronce?

    Absolutnie nie uważam, żeby to była jakakolwiek przesada i już to uzasadniam.

    tzok napisał:
    Przecież serwer/parser PHP nie wykona skryptu z pliku innego niż .php

    Błędne założenie. Często w serwerach www pokonfigurowane są katalogi, które umożliwiają uruchamianie aplikacji jako cgi. Poza tym jeśli już mam możliwość umieszczenia na serwerze pliku z prawami do wykonywania i skryptu php, to z poziomu skryptu php istnieje możliwość uruchomienia załadowanego wcześniej pliku.

    tzok napisał:
    Poza tym jeśli nie wyświetlasz wysłanych plików, to wysyłający nawet nie wie gdzie trafił plik.

    Wystarczy wykonać kilka prób dodając za każdym razem przejście o jeden poziom w drzewie katalogu powyżej, aż trafimy do katalogu głównego serwera.

    tzok napisał:
    Skrypt który podałem pochodzi z jakiegoś kursu PHP.

    Kursy mają to do siebie, że zawężają problematykę i nie opisują całości problemu.

    tzok napisał:
    Pisząc niewielkie programy na własny użytek czy jakieś proste stronki, niegy nie zakładam, że ktoś będzie chciał ich używać niezgodnie z przeznaczeniem.

    To jest duży błąd. należy pamiętać, że umieszczając na serwerze swoje oprogramowanie bierzemy odpowiedzialność za bezpieczeństwo całości serwera. Nawet jeśli założymy, że Twoje dane mają niewielką wartość trzeba pamiętać oo innych użytkownikach i ich danych.

    I dodatkowo:
    Danym podawanym przez użytkowników w systemach dostępnych "ze świata" nigdy nie można ufać, więc moja wskazówka odnośnie obcinania niebezpiecznych lub potencjalnie niebezpiecznych danych dotyczy nie tylko uploadu plików, ale wszystkich danych. Tak więc koszt wytworzenia tego kodu rozkłada się na dużą ilość oprogramowania.
    Aby zastosować wszystkie zaproponowane przez mnie rozwiązania należy dopisać nie więcej linii, niż zawiera zaprezentowany przykład.
    Należy uczyć się dobrych nawyków zawsze, gdy tylko jest to możliwe. Na kursach, w szkołach, czy na uczelniach tego nie uczą. Sprzedaję wiedzę, która wynika z doświadczenia. Na codzień zdarzają się sytuację, gdy programiści wychowani na "projektach" i stronkach domowych, przenoszą swoje nawyki na "produkty". O głośniejszych efektach tego można sobie co jakiś czas poczytać w mediach.

  • #18 01 Sty 2009 16:31
    tzok
    Moderator Samochody

    ...pokaż więc jak zrobić to dobrze.

    Jeśli serwer jest ustawiony prawidłowo skrypt uruchomiony z konta jednego użytkownika nie ma dostępu do danych na kontach innych użytkowników.
    Programista ze mnie marny, ale i tak nie potrafię sobie wyobrazić, jakie szkodzy mogłoby wywołać uploadowanie na serwer pliku z rozszerzeniem .zip (bez względu na jego faktyczną zawartość), więc tym bardziej nie potrafię się przed tym zabezpieczyć.

  • #19 01 Sty 2009 17:18
    BoskiDialer
    Poziom 34  

    tzok: Plik zip przy różnych lukach można wrzucić do innych katalogów. Istnieją też różne inne problemy. Znam co najmniej jeden przypadek, kiedy osoba wspaniałomyślnie chciała zrobić statystyki pobierania plików, więc powstał plik php, który służył do aktualizowania statystyk oraz zwracania plików. Jakie było moje zdziwienie, kiedy okazało się że plik jest zwracany przez include zamiast readfile (a można nawet zrobić przekierowanie tracąc na dokładności statystyk) - wystarczyło wrzucić dowolny plik, który pomimo rozszerzenia był interpretowany jako php (zastosowanie include). Czasem lepiej dać większe zabezpieczenia, niż zostawić lukę. W przypadku danych tekstowych szeroko stosowane regexp do walidacji danych z zewnątrz oprócz bezpieczeństwa ustrzega również przed po prostu błędnie wprowadzonymi danymi.

    Samo stosowanie wszelakich zabezpieczeń uważam za niezbędne. Pisząc dowolny skrypt w php staram się myśleć jak osoba, która chciała by bezwzględnie zwiększyć swoje uprawnienia (wykorzystując pisany kod). Zapobieganie błędom daje doświadczenie i zapobiega ewentualnej kompromitacji.

  • #20 01 Sty 2009 19:25
    tmassals
    Poziom 11  

    tzok napisał:
    ...pokaż więc jak zrobić to dobrze.

    Jeśli serwer jest ustawiony prawidłowo skrypt uruchomiony z konta jednego użytkownika nie ma dostępu do danych na kontach innych użytkowników.
    Programista ze mnie marny, ale i tak nie potrafię sobie wyobrazić, jakie szkodzy mogłoby wywołać uploadowanie na serwer pliku z rozszerzeniem .zip (bez względu na jego faktyczną zawartość), więc tym bardziej nie potrafię się przed tym zabezpieczyć.


    Przy tworzeniu jakichkolwiek aplikacji korzystających z protokołu http należy pamiętać, że wszystko co przychodzi od strony użytkownika może niekoniecznie pochodzić tylko z Firefoxa czy Explorera. Może zostać przez użytkownika spreparowane i przysłane tak, żeby aplikacji/serwerowi zrobić krzywdę. Nie wolno o tym nigdy zapominać. Do preparowania danych nie są potrzebne żadne wyszukane narzędzie. Co więcej, większość z tych narzędzi powinna być podstawą arsenału twórcy stron www. Pluginy do Firefoxa: Firebug, Live HTTP Headers, Tamper Data(do niedawna były z nim problemy), czy Modify Headers są narzędziamy Webdevelopera.
    A teraz do rzeczy:
    Skrypt korzysta z następujących danych bez jakiegokolwiek ich sprawdzenia: typ pliku, nazwa tego pliku i same dane. Wystarczy przesłać do serwera tak przygotowane dane, że będą one zawierały: typ odpowiedni dla pliku zip, nazwę i treść pliku php. Po takiej akcji na serwerze znajdzie się plik wykonywalny dla serwera, a nie zip.

    Skrypty php uruchamiane są z prawami nie użytkownika, który je stworzył, a serwera www w otoczeniu, którego zostały uruchomione. W praktyce, dla rozwiązań domowych, nie stosuje się (ze względu na koszty) takich rozwiązań, które separowałyby po stronie serwera skrypty stworzone przez poszczególnych użytkowników.

  • #21 02 Sty 2009 12:13
    tzok
    Moderator Samochody

    W takim razie, czy ktoś mógłby wskazać na sprawdzony i bepieczny kod w PHP do wysyłania plików (obrazki, archiwa) na serwer?

  • #22 02 Sty 2009 14:05
    tmassals
    Poziom 11  

    A którego konkretnie punktu z zaproponowanych przez mnie nie jesteś w stanie sam oprogramować lub znaleźć w jednym z setek tutoriali?

  • #23 02 Sty 2009 14:10
    tzok
    Moderator Samochody

    Ja może jestem w stanie znaleźć, ale dla wielu może to być problem, w końcu sam piszesz, że: "Na kursach, w szkołach, czy na uczelniach tego nie uczą.".

    Choć np. ten punkt "format przesłanego pliku sprawdzać w wiarygodny sposób, np. file lub lepiej odczytując plik przy pomocy narzędzia, które weryfikuje poprawność formatu pliku (w tym przypadku gzip)" jest dla mnie trudny do zrealizowania.

  • Pomocny post
    #24 02 Sty 2009 14:50
    Dr.Vee
    VIP Zasłużony dla elektroda

    http://php.net/manual/en/ref.fileinfo.php
    http://php.net/manual/en/function.mime-content-type.php
    http://php.net/manual/en/ref.zlib.php

    Poprawna weryfikacja formatu pliku nie oznacza jeszcze, że dane zawarte w pliku są niegroźne. Najbezpieczniej by było, gdyby serwer www wykonujący skrypty nie interpretował danych z plików wysyłanych przez użytkowników, a jedynie zmieniał ich nazwy na automatycznie wygenerowane i przenosił do katalogu niedostępnego z webroot. Inny skrypt (lub osobny serwer www) weryfikuje prawa dostępu do danego pliku przez danego użytkownika i serwuje dane z pliku do klienta.

    Pozdrawiam,
    Dr.Vee

 Szukaj w ofercie
Zamknij 
Wyszukaj w ofercie 200 tys. produktów TME