Czy htmlspecialchars i mysql real escape string chroni mój kod PHP przed wstrzyknięciem?
Wcześniej zadano pytanie dotyczące strategii walidacji danych wejściowych w aplikacjach internetowych .
Najlepsza odpowiedź, w momencie pisania, sugeruje w PHP
tylko użycie htmlspecialchars
i mysql_real_escape_string
.
6 answers
Jeśli chodzi o zapytania do bazy danych, zawsze staraj się używać gotowych zapytań parametryzowanych. Wspierają to biblioteki mysqli
i PDO
. Jest to nieskończenie bezpieczniejsze niż używanie funkcji uciekających, takich jak mysql_real_escape_string
.
Tak, mysql_real_escape_string
jest efektywnie tylko funkcją uciekającą. To nie jest magiczna kula. Wszystko, co zrobi, to ucieczka niebezpiecznych znaków, aby mogły być bezpieczne w użyciu w jednym łańcuchu zapytania. Jeśli jednak wcześniej nie odkażysz swoich wejść, będziesz podatny na ataki.
Wyobraź sobie następujący SQL:
$result = "SELECT fields FROM table WHERE id = ".mysql_real_escape_string($_POST['id']);
Powinieneś być w stanie zobaczyć, że jest to podatne na wykorzystanie.
Wyobraź sobie, że parametrid
zawierał wspólny wektor ataku:
1 OR 1=1
Nie ma tam ryzykownych znaków do kodowania, więc przejdzie prosto przez filtr uciekający. Zostawiając nas:
SELECT fields FROM table WHERE id= 1 OR 1=1
Który jest pięknym wektorem SQL injection i pozwoli atakującemu zwrócić wszystkie rzędy. Lub
1 or is_admin=1 order by id limit 1
Który wytwarza
SELECT fields FROM table WHERE id=1 or is_admin=1 order by id limit 1
Który pozwala atakującemu zwrócić dane pierwszego administratora w tym całkowicie fikcyjnym przykładzie.
Chociaż funkcje te są użyteczne, muszą być używane ostrożnie. Musisz upewnić się, że wszystkie wejścia internetowe są w pewnym stopniu zweryfikowane. W tym przypadku widzimy, że możemy być wykorzystywani, ponieważ nie sprawdziliśmy, czy zmienna, której używamy jako liczby, jest rzeczywiście numeryczna. W PHP powinieneś powszechnie używać zestawu funkcje sprawdzające, czy wejścia są liczbami całkowitymi, pływakami, alfanumerycznymi itp. Ale jeśli chodzi o SQL, zwróć uwagę na wartość przygotowanej instrukcji. Powyższy kod byłby bezpieczny, gdyby był przygotowaną instrukcją, ponieważ funkcje bazy danych wiedziałyby, że 1 OR 1=1
nie jest poprawnym literałem.
Jak dla htmlspecialchars()
. To samo pole minowe.
Jest prawdziwy problem w PHP, ponieważ ma cały wybór różnych funkcji ucieczki związanych z html, i nie ma jasnych wskazówek na dokładnie, które funkcje zrobić co.
Po pierwsze, jeśli znajdujesz się wewnątrz znacznika HTML, masz poważne kłopoty. Spójrz na
echo '<img src= "' . htmlspecialchars($_GET['imagesrc']) . '" />';
Jesteśmy już wewnątrz znacznika HTML, więc nie potrzebujemy , aby zrobić coś niebezpiecznego. Nasz wektor ataku może być po prostu javascript:alert(document.cookie)
Teraz wynikowy HTML wygląda jak
<img src= "javascript:alert(document.cookie)" />
Atak przechodzi prosto.
Jest jeszcze gorzej. Dlaczego? ponieważhtmlspecialchars
(wywołane w ten sposób) koduje tylko podwójne cudzysłowy, a nie pojedyncze. Więc gdybyśmy mieli
echo "<img src= '" . htmlspecialchars($_GET['imagesrc']) . ". />";
Nasz zły napastnik może teraz wprowadzić zupełnie nowe parametry
pic.png' onclick='location.href=xxx' onmouseover='...
Daje nam
<img src='pic.png' onclick='location.href=xxx' onmouseover='...' />
W tych przypadkach nie ma magicznej kuli, wystarczy, że SAM dokonasz oceny. Jeśli spróbujesz odfiltrować złe znaki na pewno nie. Podejmij podejście do białej listy i przepuść tylko te znaki, które są dobre. Zobacz Ściągawka XSS dla przykładów na to, jak różne wektory mogą być
Nawet jeśli używasz htmlspecialchars($string)
poza znacznikami HTML, jesteś wciąż podatny na ataki wielobajtowych wektorów charsetu.
Najskuteczniejsze jest użycie kombinacji mb_convert_encoding i htmlentities w następujący sposób.
$str = mb_convert_encoding($str, 'UTF-8', 'UTF-8');
$str = htmlentities($str, ENT_QUOTES, 'UTF-8');
Nawet to pozostawia IE6 podatnym na ataki, ze względu na sposób, w jaki obsługuje UTF. Można jednak wrócić do bardziej ograniczonego kodowania, takiego jak ISO-8859-1, dopóki użycie IE6 nie spadnie.
Aby uzyskać bardziej dogłębne badanie problemów wielobajtowych, zobacz https://stackoverflow.com/a/12118602/1820
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:32
Oprócz doskonałej odpowiedzi Cheekysoft:
- tak, zapewnią Ci bezpieczeństwo, ale tylko wtedy, gdy zostaną użyte całkowicie poprawnie. Użyj ich nieprawidłowo, a nadal będziesz podatny na ataki i możesz mieć inne problemy (na przykład uszkodzenie danych)
- Proszę zamiast tego używać zapytań sparametryzowanych(jak wspomniano powyżej). Można ich używać np. przez PDO lub przez owijarkę jak PEAR DB
- Upewnij się, że magic_quotes_gpc i magic_quotes_runtime są wyłączone przez cały czas i nigdy nie otrzymasz przypadkowo włączony, nawet na krótko. Są to wczesne i głęboko błędne próby programistów PHP, aby zapobiec problemom z bezpieczeństwem (które niszczy dane)
Tak naprawdę nie ma srebrnej kuli zapobiegającej wtryskiwaniu HTML( np. cross Site scripting), ale możesz być w stanie osiągnąć to łatwiej, jeśli używasz biblioteki lub systemu szablonów do wyprowadzania HTML. Przeczytaj dokumentację, aby dowiedzieć się, jak odpowiednio uciec od rzeczy.
W HTML, rzeczy MUSZĄ BYĆ uciekł inaczej w zależności od kontekstu. Jest to szczególnie prawdziwe w przypadku ciągów umieszczanych w Javascript.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-21 09:10:00
Zdecydowanie zgodziłbym się z powyższymi postami, ale mam jeszcze jedną drobną rzecz do dodania w odpowiedzi Cheekysoft, konkretnie:
Jeśli chodzi o zapytania do bazy danych, zawsze staraj się używać przygotowanych zapytania parametryzowane. Mysqli i Biblioteki PDO wspierają to. To jest nieskończenie bezpieczniejsze niż używanie ucieczki funkcje takie jak mysql_real_escape_string.
Tak, mysql_real_escape_string jest skutecznie tylko ciąg uciekający funkcja. To nie jest magia kula. Wszystko, co zrobi, to ucieczka niebezpiecznego znaków, aby mogły być bezpieczny w użyciu w jednym łańcuchu zapytań. Jeśli jednak nie odkażasz swojego wejść wcześniej, wtedy będziesz podatny na ataki.
Wyobraź sobie następujący SQL:
$ wynik = " wybierz pola z tabeli WHERE id = ".mysql_real_escape_string($_POST['id']);
Powinieneś widzieć, że to podatny na wykorzystywanie. Wyobraź sobie id parametr zawierał wspólny atak wektor:
1 lub 1=1
Nie ma tam ryzykownych chars do kodować, więc przejdzie prosto przez filtr uciekający. Zostawić us:
SELECT fields FROM table WHERE id = 1 OR 1=1
Zakodowałem małą, szybką funkcję, którą umieściłem w mojej klasie bazy danych, która usunie wszystko, co nie jest liczbą. Używa preg_replace, więc jest trochę bardziej Zoptymalizowana funkcja, ale działa w szczypta...
function Numbers($input) {
$input = preg_replace("/[^0-9]/","", $input);
if($input == '') $input = 0;
return $input;
}
Więc zamiast używać
$ wynik = " SELECT fields FROM table WHERE id =".mysqlrealescapestring("1 OR 1=1");
Użyłbym
$ wynik = " SELECT fields FROM table WHERE id =".Numbers("1 OR 1=1");
I bezpiecznie uruchomi zapytanie
SELECT fields FROM table WHERE id = 111
Jasne, że po prostu powstrzymało to wyświetlanie poprawnego wiersza, ale nie sądzę, że jest to duży problem dla kto próbuje wprowadzić sql do twojej strony;)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-22 17:26:11
Ważnym elementem tej układanki są konteksty. Ktoś wysyła "1 lub 1=1" jako ID nie jest problemem, jeśli cytujesz każdy argument w zapytaniu:
SELECT fields FROM table WHERE id='".mysql_real_escape_string($_GET['id'])."'"
Co daje:
SELECT fields FROM table WHERE id='1 OR 1=1'
Co jest nieskuteczne. Ponieważ unikasz ciągu znaków, wejście nie może wyrwać się z kontekstu łańcucha. Przetestowałem to w wersji 5.0.45 MySQL i użycie kontekstu ciągów znaków dla kolumny integer nie powoduje żadnych problemów.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-22 17:38:54
$result = "SELECT fields FROM table WHERE id = ".(INT) $_GET['id'];
Działa dobrze, nawet lepiej na systemach 64 bitowych. Uważaj na ograniczenia systemów dotyczące adresowania dużych liczb, ale w przypadku identyfikatorów baz danych działa to świetnie w 99% przypadków.
Powinieneś używać jednej funkcji/metody do czyszczenia swoich wartości, jak również. Nawet jeśli ta funkcja jest tylko opakowaniem dla mysql_real_escape_string (). Dlaczego? Ponieważ pewnego dnia, gdy zostanie znaleziony exploit do preferowanej metody czyszczenia danych, musisz go zaktualizować tylko w jednym miejscu, a nie w całym systemie znajdź i wymień.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-10-04 21:32:26
Dlaczego, och, dlaczego, nie zawierać cudzysłowy wokół wejścia użytkownika w instrukcji sql? wydaje się całkiem głupie nie! włączenie cudzysłowów w poleceniu sql uczyniłoby "1 lub 1=1" bezowocną próbą, prawda?
Więc teraz, powiesz, " co jeśli użytkownik zawiera cytat (lub podwójne cudzysłowy) w wejściu?"
Cóż, Łatwa poprawka: po prostu usuń cudzysłowy wprowadzone przez użytkownika. eg: input =~ s/'//g;
. wydaje mi się, że wejście użytkownika byłoby zabezpieczone...
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-17 19:02:46