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.

Moje pytanie brzmi: czy to zawsze wystarczy? Powinniśmy wiedzieć więcej? Gdzie te funkcje się rozpadają?
Author: Community, 2008-09-21

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

 231
Author: Cheekysoft,
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.

 9
Author: MarkR,
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;)

 3
Author: BrilliantWinter,
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.
 2
Author: Lucas Oman,
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ń.

 2
Author: cnizzardini,
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...

 -3
Author: Jarett L,
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