Ta "wystarczająco dobra" walidacja to Twoje największe zagrożenie. Podatności w mechanizmach uploadu plików
Trzy hostingi, jeden błąd — tydzień, który pokazał prawdziwy problem
Wszystko zaczęło się od jednego tygodnia
Trzy niezależne firmy hostingowe ogłosiły w tym samym tygodniu poważne luki w swoich systemach. We wszystkich przypadkach chodziło o ten sam typ podatności — nieautoryzowane uploadowanie plików. Dla badaczy bezpieczeństwa to nie był szok. To było deja vu.
Problem tkwi w tym, co łączyło te wszystkie przypadki: każda luka wynikała z tego samego, dobrze znanego błędu. Nazywam go walidacją na skróty.
Czym jest walidacja na skróty?
Wyobraź sobie, że budujesz formularz do wysyłania zdjęć. Co robisz? Sprawdzasz rozszerzenie pliku. Weryfikujesz deklarowany typ MIME. Upewniasz się, że rozmiar nie przekracza limitu. Brzmi sensownie, prawda?
Problem polega na tym, że to właśnie są skróty. Nie mówię, że te sprawdzenia są złe — mówię, że są niekompletne. I to właśnie ta niekompletność tworzy dziury w zabezpieczeniach.
Walidacja na skróty to podejście, gdzie wykonujesz minimum pracy i zakładasz, że plik jest bezpieczny. Jakbym sprawdzał, czy paczka wygląda niewinnie, zamiast ją dokładnie otworzyć i przejrzeć.
Atakujący doskonale wiedzą, jak obejść te powierzchowne zabezpieczenia. Tworzą pliki, które przechodzą podstawowe testy, ale zawierają ukryty złośliwy kod.
Anatomia podatności na nieautoryzowany upload
Przyjrzyjmy się, jak wyglądała struktura tych luk:
Po pierwsze — słaba walidacja rozszerzeń. Serwery akceptowały podwójne rozszerzenia w stylu malicious.php.jpg lub rzadziej używane formaty wykonywalne jak .phtml czy .phar.
Po drugie — brak weryfikacji zawartości. Serwer nigdy nie analizował tego, co faktycznie znajduje się w pliku. Pozwalało to na tak zwane polyglot files — pliki, które wyglądają jak obrazy, ale zawierają kod do wykonania.
Po trzecie — niebezpieczne przechowywanie. Pliki lądowały w katalogach dostępnych z poziomu internetu, bez żadnych dodatkowych zabezpieczeń.
Po czwarte — brak blokady wykonania. Konfiguracja serwera nie uniemożliwiała uruchomienia wgranych skryptów.
Kiedy te czynniki działają razem, efekt jest prosty: atakujący bez żadnego logowania mógł wgrać i wykonać dowolny kod na serwerze.
Dlaczego programiści wciąż to robią?
Zrozumienie przyczyn to pierwszy krok do ich wyeliminowania.
Presja czasu — w środowisku produkcyjnym liczy się szybkość wdrożeń. Pełna walidacja wydaje się zbędnym obciążeniem, szczególnie kiedy „sprawdzenie rozszerzenia działało w testach".
Fałszywe poczucie bezpieczeństwa — środowiska testowe rzadko zawierają złośliwe pliki. Walidatory przechodzą, developerzy wdrażają kod, a produkcja pokazuje prawdziwe oblicze.
Brak świadomości zagrożeń — nie każdy programista ma za sobą szkolenie z bezpieczeństwa. Mogą nie wiedzieć, jak kreatywnie można manipulować uploadem plików.
Zakładanie, że ktoś inny się tym zajął — zespoły czasem zakładają, że zabezpieczenia znajdują się gdzieś indziej: WAF, hardening serwera. To niebezpieczne myślenie.
Jak budować prawdziwie bezpieczny upload plików
Ochrona wymaga podejścia warstwowego. Oto jak to robić dobrze:
1. Weryfikuj typ pliku na podstawie zawartości
Zamiast polegać na rozszerzeniu czy deklaracji przeglądarki, sprawdź co plik faktycznie zawiera:
import magic
# Odczytaj pierwsze 1024 bajty do analizy
mime_type = magic.from_buffer(file.read(1024), mime=True)
file.seek(0) # Cofnij wskaźnik na początek
if mime_type in ALLOWED_MIME_TYPES:
save_file(file)
Biblioteki takie jak python-magic analizują strukturę pliku, nie tylko jego nazwę.
2. Generuj bezpieczne nazwy plików
Nigdy nie używaj oryginalnej nazwy dostarczonej przez użytkownika:
import uuid
import os
# Usuń wszystkie rozszerzenia i stwórz nową, bezpieczną nazwę
secure_filename = f"{uuid.uuid4().hex}.{allowed_extension}"
filepath = os.path.join(UPLOAD_DIR, secure_filename)
3. Przechowuj pliki poza web rootem
To absolutnie niezbędne dla aplikacji obsługujących wrażliwe dane. Jeśli pliki muszą być dostępne, serwuj je przez skrypt, który waliduje autoryzację i nie ujawnia prawdziwej ścieżki.
4. Zablokuj wykonanie na poziomie serwera
W konfiguracji Apache:
<Directory "/var/www/uploads">
<FilesMatch "\.(php|phtml|phar|py|pl|exe)$">
Order Deny,Allow
Deny from all
</FilesMatch>
</Directory>
5. Dodaj dodatkowe warstwy walidacji
- Weryfikacja sygnatur plików — sprawdzenie „magicznych bajtów" na początku pliku
- Sanityzacja obrazów — ponowne kodowanie przez bezpieczną bibliotekę typu imagemagick
- Limity wymiarów — nie tylko rozmiaru, ale też dla obrazów
- Rate limiting — uniemożliwienie masowego wgrywania plików
Ludzki wymiar problemu
Za każdą techniczną luką stoją prawdziwi ludzie:
- Klienci, których dane zostają skompromitowane
- Firmy, które płacą kary regulacyjne i odszkodowania
- Programiści, których kariera cierpi przez błędy, których można było uniknąć
- Użytkownicy, którzy zaufali usłudze, która ich zawiodła
Bezpieczeństwo to nie funkcja — to odpowiedzialność.
Co teraz powinny zrobić firmy hostingowe?
Jeśli prowadzisz platformę hostingową lub budujesz system uploadu plików:
- Przeskanuj istniejący kod pod kątem walidacji na skróty
- Wdróż prawdziwą weryfikację typu zawartości
- Przenieś wgrane pliki poza katalogi dostępne z sieci
- Dodaj reguły WAF jako dodatkową warstwę
- Przygotuj procedury reagowania na incydenty bezpieczeństwa
- Zainwestuj w szkolenia dla zespołów deweloperskich
Podsumowanie
Luki odkryte w tamtym tygodniu nie wynikały z wyrafinowanych ataków ani nieznanych exploitów. Były efektem skrótów programistycznych. I to powinno być pocieszające — oznacza to, że poprawki są w zasięgu ręki.
Bezpieczeństwo nie musi być wolne ani bolesne. Wymaga jednak przejścia od „wystarczy" do kompleksowego, warstwowego podejścia. Pytanie nie brzmi, czy Twoja aplikacja zostanie przetestowana — pytanie brzmi, czy przejdzie ten test.
Poświęć czas na właściwą walidację. Twoi użytkownicy na tym polegają.