Na blogu SecuriTeam pojawił się wpis File upload security recommendations. Warto się z nim zapoznać i stosować zawarte tam zalecenia. Ogólnie - im mniej użytkownik ma kontroli nad tym gdzie i jak plik zostanie zapisany na serwerze, tym lepiej.
Upload plików: File upload security recommendations
W zasadzie chciałem podać tylko link do tego wpisu, ale może jeszcze kilka dodatkowych uwag.
Sprawdzanie typu MIME może nie być wystarczające. Wiele zależy od tego, na jakiej podstawie typ ten jest określany. Jeśli jest on określany na podstawie parametrów przesłanych przez klienta, to takie "zabezpieczenie" nie jest nic warte. To klient (w szczególności atakujący) kontroluje jaka będzie wartość typu MIME, wcale nie musi być prawdziwa. Ustalanie typu MIME po informacjach zawartych w samym pliku (np. po jego nagłówku) też nie koniecznie jest skuteczną metodą. W wielu przypadkach można na początku umieścić kawałek danych (nagłówek pliku), który spowoduje, że plik zostanie rozpoznany jako dozwolony typ MIME, w praktyce będzie jednak zawierał dane zupełnie innego rodzaju. Mimo tych wszystkich ograniczeń/niedoskonałości, należy wykorzystać listę dozwolonych typów MIME. Powtarzam - listę dozwolonych, a nie niedozwolonych.
Rozszerzenie pliku jest ciężej sfałszować (pomijam tu różne ataki powodujące, że inne rozszerzenie widziane przez "moduł sprawdzenia rozszerzenia" jest inne niż to, z jakim plik rzeczywiście zostanie utworzony). Co więcej to właśnie rozszerzenie często decyduje jak dany plik zostanie potraktowany przez serwer. Na przykład umieszczenie na serwerze pliku *.php może spowodować wykonanie kodu w nim zawartego, jeśli atakującemu uda się odwołać do tego pliku. By to utrudnić (bezpośrednie odwołanie do pliku), zastosowanie losowych nazw katalogów i plików ma sens, przy czym wszystko zależy od konkretnej sytuacji. Może okazać się, że w konkretnym scenariuszu lepszym rozwiązaniem będzie na przykład zapisanie plików poza katalogami dostępnymi dla serwera WWW.
Przy okazji jeden ciekawy scenariusz ataku: aplikacja ogranicza listę typów plików, jakie mogą zostać przekazane przez użytkownika. W szczególności nie są dozwolone pliki wykonywalne (np. *.php, *.cgi). Okazuje się jednak, że można przekazać plik o nazwie .htaccess (swoją drogą dobre uzasadnienie, dlaczego warto ustawić AllowOverride na None). Pozostaje tylko w tym pliku zmapować pliki o "niegroźnym" rozszerzeniu do PHP.
Warto zauważyć również, że ograniczenie wielkości przekazywanego pliku samo w sobie nie rozwiązuje problemu z możliwością ataku DoS przez wyczerpanie miejsca na dysku. W sumie co za różnica, czy zostanie przekazanych 10 plików po 100 MiB czy 1000 plików po 1 MiB? Przecież atakujący nie będzie robił tego ręcznie chyba, że będzie musiał (np. konieczność wypełnienia CAPTCHA).
Warto, jak zawsze, zapoznać się również z OWASP Development Guide 2.0.
I jeszcze jedno - nie każda firma/osoba może pozwolić sobie na utrzymywanie własnego serwera WWW, w związku z czym nie zawsze można utrzymywać swoją stronę/aplikację w pełni kontrolowanym przez siebie środowisku. Wykorzystanie do tego celu firm hostingowych jest zupełnie normalnym pomysłem, z akceptacją którego nie mam problemów, przynajmniej co do zasady. W chwili, gdy aplikacja jest naprawdę istotna lub przetwarza/zawiera istotne dane (np. dane osobowe, ale takie "trochę bardziej pełne") wykorzystanie do jej hostowania zwykłego serwera wirtualnego u najtańszego dostawcy, uważam za pomysł co najmniej mocno średni.