Witam,
jak zabezpieczyć(ogólnie) upload plików na serwer bez ograniczeń typów oraz wielkości, da się w ogóle?.
Witam,
jak zabezpieczyć(ogólnie) upload plików na serwer bez ograniczeń typów oraz wielkości, da się w ogóle?.
Da się zabezpieczyć :)
podałeś że chcesz bez ograniczeń typów oraz wielkości - ale co rozumiesz przez zabezpieczenie w takim razie? Oczywiście możesz zaimplementować kontrole dostępu (nie każdy może uploadować). Wiadomo - tylko zarejestrowani userzy.
Dalej - to już inwencja twórcza. Jeśli chcesz dać bezpośredni dostęp do plików uploadowanych (jako download) to musisz w htaccess na pewno wyłączyć przetwarzanie/interpretacje plików przez serwer, czyli jak ktoś Ci wgra php to serwer ma tego nie wykonywać. To samo w sumie jeśli dostęp do pliku ma być przez bramkę w postaci skryptu - jasne że możesz czytać plik, ale nigdy go nie includować/uruchamiać.
Oprócz powyższego jest jeszcze parę zasad - po pierwsze NIGDY nie ufaj użytkownikowi. Nie idź na ślepo za $_FILES
tylko sprawdź czy faktycznie jest w danych i w pliku. Możesz być wybredny i zakładać z góry że jeśli jakieś dane w $_FILES
odnośnie pliku są błędne to cały plik jest zły (np size != filesize(uploaded)
). Nigdy nie wierz w to co mówi rozszerzenie pliku, sprawdzaj MIME ale po stronie serwera ($_FILES
ma mime, ale to ignoru/porównuj ze stanem faktycznym i patrz poprzednie porady). Sprawdzaj rozmiar pliku, nie pozwalaj ludziom na przekroczenie jakichś rozmiarów itp
Jeszcze jeśli masz możliwość - daj po stronie klienta walidację np w JS, ukryte pola, cuda bajery (;)) co by jakimś botem nie można było łatwo słać a po stronie serwera nie ufaj w ogóle plikom i skanuj je jakimś antyvierm/antymalware itp.
Ostatnia rzecz: jeśli dasz możliwość wgrywania archiwów - nigdy, ale to przenigdy nie dawaj możliwości ich rozpakowywania przez php. To jak prosić o zabicie serwera ;)
Johnny_Bit, dzięki! za solidną i konstruktywną odpowiedź.
Jeżeli chodzi o dostęp do plików to userzy nie mogą wyświetlać katalogu, w którym są pliki. Używam popularnego frameworka MVC Yii2.
Każdy user po upload-zie do pobrania pliku dostaję link w postaci:
http://serwer/kontroler/akcja/nr_identyfikacyjny/nr_identyfikacyjny, numery są generowane losowo i zapisane w bazie danych za pomocą ich mój skrypt identyfikuję jaki plik ma wyczytać, tak wygląda akcja odpowiedzialna za udostępnienie pliku:
/**
* @param int $time
* @param string $access_key
* @return null
*/
public function actionDownload($time, $access_key)
{
$model = new GlobalFile;
$file = $model->download($time, $access_key); //zapytanie SQL o istnienie pliku. Zwraca położenie pliku.
if (is_null($file) || !file_exists($file->getAbsolutePath()))
{
throw new NotFoundHttpException('Sorry your file is not exists.');
}
$absolutePath = $file->getAbsolutePath();
header('Content-Type: application/zip');
header('Content-disposition: attachment; filename=' . basename($absolutePath ));
header('Content-Length: ' . filesize($absolutePath ));
readfile($absolutePath );
}
Zawartość zwracam z typem "application/zip", ponieważ każdy plik po upload-zie jest pakowany do zipa.
W którym miejscu mogą mi się wykonać upload-owane pliki?.
przy takim podejściu - nie mogą się wykonać, więc jest ok :) download nie jest straszny. za to ten zip... @Gynvael Coldwind miał kiedyś prezentacje co może wyjść nie tak z zipami, ale nic z tego nie pamiętam oprócz tego że przy złym wietrze może byc niezłe kuku...
Ja przy upload/download wychodze z założenia że nie modyfikuje nawet 1 bit w pliku od uzytkownia i nie pozwalam go w jakikolwiek sposób czemukolwiek interpretować... No chyba że obrazy, ale w nich to robię strip na wszystko łącznie z exif/komentarzami/czymkolwiek co by gdzieś mogło przemycić cokolwiek ;)
No ja nie mam wyboru zip musi być. Tyle że do zip-u używam linuxa, po udanym upload-zie odpalam w konsoli program zip i gotowe.
Jak teraz sprawdzić, czy wrzucany plik nie posiada robaków - musiałbym to robić przed wrzuceniem przez PHP do tmp plików, jak rozumiem rozwiązanie leży po stronie serwera - jakiś program anty-wirusowy z automatycznym sprawdzaniem nowo pojawiających się plików + obsługa wyjątków PHP przy próbie przeniesienia nieistniejącego piku(wcześniej usuniętego przez anty-wirusa). Ciekawe jak rozwiązują te problemy tacy giganci jak GitHube, Google Dysk, Bitbucket - wiem, wiem na pewno nie korzystają z PHP :)
PHP pliku uploadowane wrzuca domyślnie w /tmp. po skończonym uploadze możesz uruchomić na pliku na żądanie skan, jak plik zostanie wywalony to przecież będziesz mieć że !file_exists($uploaded_file)
i możesz dać do usera że "nasz system wykrył potencjalne niebezpieczeństwo w pliku przesłanym przez Ciebe. Sprawdź swój komp czy nie masz syfu, a jak bardzo się upierasz że nie masz syfu i koniecznie chcesz przesłać plik - skontaktuj sie z działem supportu".
Google - kiedyś na gmailu nie dało się przesłać żadnych wykonywalnych i jeszcze jakieś ograniczenia mieli. Po uploadze było "skanowanie plików" i jak nie przeszło to plik znikał ;) nie wiem jak reszta :)