LAB_03 / PLIKI Średni
Rozszerzenie to za mało. Przetestuj rzeczywistą walidację plików.
Wskazówka do eksperymentu
Najpierw sprawdź zwykłe dane wejściowe. Następnie użyj przykładu z lekcji i porównaj wynik w wariancie podatnym oraz zabezpieczonym. W panelach kodu zaznaczono miejsca istotne dla ataku lub obrony.
Przesyłanie plików
01 / TEORIA · ⚠ PODATNY KOD
Podatny wariant
Przesyłanie plików jest krytycznym punktem aplikacji. Nieodpowiednia walidacja może prowadzić do wyczerpania zasobów, a w niektórych aplikacjach nawet do przejęcia serwera.
W podatnym wariancie właściwości plików, takie jak typ lub rozmiar, nie są rzetelnie sprawdzane. Przykład niewystarczającego zabezpieczenia stanowi poniższy kod.
<input type="file" name="fileToUpload" id="fileToUpload" accept="image/*">
Podjęto próbę ograniczenia typu przesyłanych plików, za pomocą atrybutu "accept". Aby obejść to zabezpieczenie wystarczy skorzystać z narzędzia DevTools i usunąć ten fragment kodu HTML, a następnie przesłać plik niebędący obrazem. Co więcej, nie został ograniczony maksymalny rozmiar pliku, zatem atakujący móglby spróbować obciążyć serwer wieloma plikami o dużym rozmiarze.
Poniższy formularz polega wyłącznie na atrybucie HTML sprawdzanym w przeglądarce.
02 / ATAK · PRZETESTUJ DANE WEJŚCIOWE
03 / OBRONA · ✓ ZABEZPIECZONY KOD
Zabezpieczony wariant
Aby uniknąć ingerencji użytkownika w zabezpieczenia systemu, nie należy umieszczać ich w sekcji dostępnej dla użytkownika za pomocą narzędzi deweloperskich. Poniżej przedstawione zabezpieczenia wykonywane są po stronie serwera.
Pierwszym krokiem jest sprawdzenie typu przesyłanego pliku. W przykładowym kodzie poniżej celem jest upewnienie się, że plik jest obrazem.
$correct = 0;
@$check_error = getimagesize($_FILES["fileToUpload"]["tmp_name"]);
// Checking if an actual image
if( $check_error!== false) {
// Image
$correct = 1;
} else {
// Not an image
$correct = 0;
}
// Check the extension
$imageFileType = strtolower(pathinfo($target_file,PATHINFO_EXTENSION));
$uploaded_type = $_FILES[ 'fileToUpload' ][ 'type' ];
if($imageFileType != "jpg" && $imageFileType != "png" && $imageFileType != "jpeg"
&& $imageFileType != "gif") {
//Wrong extension
$correct = 0;
}
Funkcja getimagesize() odczytuje informacje o obrazie i zwraca false, jeśli plik nie jest rozpoznany jako obraz. Funkcja pathinfo() pozwala wyodrębnić rozszerzenie i porównać je z dozwolonymi rozszerzeniami obrazów.
Aby usunąć metadane, można ponownie zakodować obraz za pomocą funkcji imagecreatefromjpeg() lub imagecreatefrompng() i odpowiedniej funkcji zapisu obrazu. Poniższy kod ilustruje to podejście.
if( $uploaded_type == 'image/jpeg' ) {
$img = imagecreatefromjpeg( $uploaded_tmp );
imagejpeg( $img, $temp_file, 100);
}
else {
$img = imagecreatefrompng( $uploaded_tmp );
imagepng( $img, $temp_file, 9);
}
imagedestroy( $img );
Kolejnym krokiem jest sprawdzenie, czy rozmiar pliku mieści się w określonych granicach. Poza maksymalnym rozmiarem warto jest sprawdzić, czy rozmiar nie jest równy 0 bajtów. Niezabezpieczony system może pozwalić użytkownikowi przesłać dowolną liczbę plików 0-bajtowych, ponieważ ich rozmiar nawet po zsumowaniu nie przekroczy żadnej ustalonej granicy. Jest to jednak ryzykowne, ponieważ pomimo zerowego rozmiaru, przechowywanie takich plików wciąż zajmuje pewną ilość pamięci związaną w tym wypadku nie z danymi (zawartością pliku), ale metadanymi (właściwościami samych plików, np. ich nazwami).
// Check the size
if ($_FILES["fileToUpload"]["size"] > 100000 or $_FILES["fileToUpload"]["size"] == 0 ) {
//Too large
$correct = 0;
}
Przetestuj poniższy formularz i porównaj wynik kontroli po stronie serwera z podatnym wariantem. Sprawdź rzeczywistą walidację obok przedstawionych przykładów.