Dziś bardzo krótko, bez zbędnych dywagacji, czyli tylko i wyłącznie o tablicy $_SERVER. Dbając o bezpieczeństwo aplikacji webowych zwraca się uwagę na wiele czynników, jakimi są SQL injections, przechwytywanie nieprawidłowych parametrów, uogólniające zapytania przepuszczające maskę % w LIKE zapytaniu do baz, XSS‘y w $_POST, $_GET.
I finalnie… wiele osób zapomina (a jeszcze więcej nie jest tego świadom) o możliwości wstrzyknięcia szkodliwych danych w $_SERVER['HTTP_X_FORWARDED_FOR'];. Konsekwencje są oczywiście katastrofalne.
O ile sama walidacja jest rzeczą wtórną, diabeł tkwi w trzech szczegółach:
X-Forwarded-For).document.cookie i przesłać je sobie na serwer w dowolny sposób, zatem atakowi nie ulegną osoby trzecie.ip2long() i zapis w zupełności nieprzydatnych nam później danych do bazy.Przykład tampingu danych, żeby spreparować niepożądane efekty.
Mamy bardzo prosty, niebezpieczny kod funkcji, która pobiera pierwszy adres na liście adresów oddzielonych przecinkami z $_SERVER['HTTP_X_FORWARDED_FOR'] o ile istnieje, natomiast w przeciwnym wypadku $_SERVER['REMOTE_ADDR']:
< ?php function getUserIp() { if(isset($_SERVER['HTTP_X_FORWARDED_FOR'])) return trim(current(explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']))); return $_SERVER['REMOTE_ADDR']; } $sUserIP = getUserIp(); echo 'Hi "' . $sUserIP . '"!'; // first bug while display. var_dump(ip2long($sUserIP)); // second bug while transforming data. ?>
Pora na przykład manipulacji takich danych.
$_POST, $_GET, $_COOKIE, nagłówki, “w locie żądania” etc.X_FORWARDED_FOR=<script>alert('Test.')</script>Naszym oczom ukazują się co najmniej dwa błędy. Pierwszy to błąd prezentacji danych, który wykorzystuje <script>. O ile nie musimy się tym przejmować, bo naturalnie takie żądania nie są tak łatwo wysyłane, użytkownik nie może paść ofiarą ataku przez kliknięcie w link, który np. ukradnie mu ciasteczka. Dane nagłówkowe nie są w stanie być zmodyfikowane poprzez kliknięcie w link, podobnie jak z danymi $_POST (oczywiście mówimy o przypadkach trywialnych, bez javascript’owych wymuszanych submitów targetowanych do np. ramek).
Znacznie poważniejszym błędem jest konsekwencja wadliwego formatu danych, które nasza funkcja bagatelizuje. Po pierwsze mamy fałszywe dane zwracane przez ip2long(), po drugie kto powiedział, że właśnie z tej funkcji korzystamy, a nie zapisujemy danych plain’em i nie bindujemy pofiltrowanych danych lub instrukcji warunkowych zapytania przez np. sprawdzony ORM.
Rozwiązanie problemu.
Edit: Jak słusznie zauważył Zyx, zapomniałem o tym wspomnieć, że skoro mogą znaleźć się tam dowolne dane przesłane od użytkownika, nie należy tego pola traktować jako wyznacznik, że jest to numer jego IP, jest ono bezużyteczne i powoduje potencjalną lukę. Poza zabezpieczeniami to podstawowy argument, żeby o polu zapomnieć i używać $_SERVER['REMOTE_ADDR'].
Po pierwsze funkcja powinna sprawdzać dane wejściowe chociażby preg_match() lub konwersją do ip2long() i (jeżeli jest taka potrzeba) spowrotem do long2ip(). Dwa, pamiętajmy, że w X_FORWARDED_FOR znajdują się śmieci, adresy lokalne sieci, itd., które należy pominąć przy wyborze adresu z listy po przecinku.
Zabezpieczenie jest trywialne: nigdy nie korzystać z tego pola. W 99% przypadków adresu IP użytkownika potrzebujemy do celów bezpieczeństwa. Jak można polegać na polu z nagłówka HTTP, gdzie każdy może wpisać sobie dosłownie cokolwiek? Pal sześć już błędne dane, ale przecież można tam wpisać DOWOLNY poprawny adres IP i oszukać w ten sposób nawet najwymyślniejsze zabezpieczenia. Jak ktoś nie wierzy, to może sobie poszukać – dawno temu z powodu zaufania temu właśnie nagłówkowi można było włamać się do phpBB.
Zatem chcesz mieć adres IP użytkownika? Korzystaj z $_SERVER['REMOTE_ADDR'], a o reszcie zapomnij.
@Zyx dobrze prawi. Dlatego wpis dotyczy ataku na to pole. Wiele osób jest tego nieświadomych, że tam mogą być dowolne dane.