Ochrona przed SQL Injection - podstawy
1. Czym jest SQL Injection?
Ataki typu SQL Injection polegają na "wstrzeleniu się" w zapytanie do bazy danych ze swoim kodem. Niestety wiele stron jest podatnych na ataki tego typu.
2. Na czym to polega?
Przykładem prostego SQL Injectiona jest nieprzefiltrowane zapytanie do bazy danych w skrypcie logowania.
Co tu jest nie tak? Wpiszmy zamiast użytkownika lub hasła znak '. Co się stało? Naszym oczom ukazał się błąd bazy danych. Ale jak to wykorzystać? MySQL ma bardzo wiele ciekawych funkcji, np. kiedy otworzymy komentarz, nie musimy go zamykać. Wpiszmy zamiast użytkownika coś takiego: ' or 1=1 /* a zamiast hasła byle co np.: blablabla. Zapytanie będzie wyglądało następująco:
SELECT * FROM uzytkownicy WHERE user='' or 1=1 /*' AND haslo='blablabla'
Kawałek zaznaczony na czerwono to podany przez nas użytkownik. Co dało nam /*? Zakomentowaliśmy całą resztę zapytania, która nie zostanie wykonana, czyli: ' AND haslo='blablabla'. Tak spreparowane zapytanie zawsze zwróci nam wartość TRUE (no chyba że 1≠1).
3. Jak się bronić?
Istnieją dwa rozwiązania. Oba są proste. Można użyć funkcji addslashes(), czyli kod powinien wyglądać tak:
Lub można używać htmlspecialchars():
Teraz nie musimy się obawiać ataku SQL Injection. Ale zostaje problem, gdy korzystam z htmlspecialchars() wtedy, jak to odczytuję, pokazują mi się dziwne znaki.
4. Jak to odczytać?
Jeżeli użyliście addslashes wtedy po prostu je odczytujecie z bazy danych. Ale, gdy używacie htmlspecialchars() - należy napisać własną funkcję która zamienia znaki. To jest przykład:
Po pobraniu funkcji musicie przepuścić ją przez funkcję format_html(). Jeżeli znak nie jest dodane do tej funkcji - możecie sami go dodać.
5. Jeszcze inaczej:
Warto sprawdzać dane jeszcze przed wciśnięciem ich w zapytanie i obsłużyć ewentualne błędy (np logować ip skąd biorą się takie błędy jeśli będzie się to powtarzać można zablokować stronę dla takiej osoby) dane których nie można weryfikować można przepuścić przez mysql_real_escape_string (uwaga przed użyciem tej funkcji musi być otwarte połączenie z bazą i trzeba pamiętać by mimo wszystko używać na zewnątrz cudzysłowu ograniczającego treść)
Ataki typu SQL Injection polegają na "wstrzeleniu się" w zapytanie do bazy danych ze swoim kodem. Niestety wiele stron jest podatnych na ataki tego typu.
2. Na czym to polega?
Przykładem prostego SQL Injectiona jest nieprzefiltrowane zapytanie do bazy danych w skrypcie logowania.
$query = mysql_query("SELECT * FROM uzytkownicy WHERE user='".$_POST['user']."' AND haslo='".$_POST['haslo']."'");
Co tu jest nie tak? Wpiszmy zamiast użytkownika lub hasła znak '. Co się stało? Naszym oczom ukazał się błąd bazy danych. Ale jak to wykorzystać? MySQL ma bardzo wiele ciekawych funkcji, np. kiedy otworzymy komentarz, nie musimy go zamykać. Wpiszmy zamiast użytkownika coś takiego: ' or 1=1 /* a zamiast hasła byle co np.: blablabla. Zapytanie będzie wyglądało następująco:
SELECT * FROM uzytkownicy WHERE user='' or 1=1 /*' AND haslo='blablabla'
Kawałek zaznaczony na czerwono to podany przez nas użytkownik. Co dało nam /*? Zakomentowaliśmy całą resztę zapytania, która nie zostanie wykonana, czyli: ' AND haslo='blablabla'. Tak spreparowane zapytanie zawsze zwróci nam wartość TRUE (no chyba że 1≠1).
3. Jak się bronić?
Istnieją dwa rozwiązania. Oba są proste. Można użyć funkcji addslashes(), czyli kod powinien wyglądać tak:
$usr = addslashes($_POST['user']);
$pas = addslashes($_POST['haslo']);
$query = mysql_query("SELECT * FROM uzytkownicy WHERE user='".$usr."' AND haslo='".$pas."'");
$pas = addslashes($_POST['haslo']);
$query = mysql_query("SELECT * FROM uzytkownicy WHERE user='".$usr."' AND haslo='".$pas."'");
Lub można używać htmlspecialchars():
$usr = htmlspecialchars($_POST['user']);
$pas = htmlspecialchars($_POST['haslo']);
$query = mysql_query("SELECT * FROM uzytkownicy WHERE user='".$usr."' AND haslo='".$pas."'");
$pas = htmlspecialchars($_POST['haslo']);
$query = mysql_query("SELECT * FROM uzytkownicy WHERE user='".$usr."' AND haslo='".$pas."'");
Teraz nie musimy się obawiać ataku SQL Injection. Ale zostaje problem, gdy korzystam z htmlspecialchars() wtedy, jak to odczytuję, pokazują mi się dziwne znaki.
4. Jak to odczytać?
Jeżeli użyliście addslashes wtedy po prostu je odczytujecie z bazy danych. Ale, gdy używacie htmlspecialchars() - należy napisać własną funkcję która zamienia znaki. To jest przykład:
function format_html($val)
{
if ( $val == "" )
{
return "";
}
$val = str_replace( "&" , "&" , $val );
$val = str_replace( "<!--" , "<!--" , $val );
$val = str_replace( "-->" , "-->" , $val );
$val = str_replace( ">" , ">" , $val );
$val = str_replace( "<" , "<" , $val );
$val = str_replace( """ , '"' , $val );
$val = str_replace( "$" , "$" , $val );
$val = str_replace( "" , "\r" , $val );
$val = str_replace( "!" , "!" , $val );
$val = str_replace( "'" , "'" , $val );
return $val;
}
{
if ( $val == "" )
{
return "";
}
$val = str_replace( "&" , "&" , $val );
$val = str_replace( "<!--" , "<!--" , $val );
$val = str_replace( "-->" , "-->" , $val );
$val = str_replace( ">" , ">" , $val );
$val = str_replace( "<" , "<" , $val );
$val = str_replace( """ , '"' , $val );
$val = str_replace( "$" , "$" , $val );
$val = str_replace( "" , "\r" , $val );
$val = str_replace( "!" , "!" , $val );
$val = str_replace( "'" , "'" , $val );
return $val;
}
Po pobraniu funkcji musicie przepuścić ją przez funkcję format_html(). Jeżeli znak nie jest dodane do tej funkcji - możecie sami go dodać.
5. Jeszcze inaczej:
Warto sprawdzać dane jeszcze przed wciśnięciem ich w zapytanie i obsłużyć ewentualne błędy (np logować ip skąd biorą się takie błędy jeśli będzie się to powtarzać można zablokować stronę dla takiej osoby) dane których nie można weryfikować można przepuścić przez mysql_real_escape_string (uwaga przed użyciem tej funkcji musi być otwarte połączenie z bazą i trzeba pamiętać by mimo wszystko używać na zewnątrz cudzysłowu ograniczającego treść)
$usr = preg_match('/^[0-9]*$/', $_POST['user'])?$_POST['user']:FALSE;
if ($usr) {
$query = mysql_query("SELECT * FROM uzytkownicy WHERE user='" . $usr . "' AND haslo='" . mysql_real_escape_string($_POST['haslo']) . "'");
} else {
print 'Błędne dane wejściowe';
}
if ($usr) {
$query = mysql_query("SELECT * FROM uzytkownicy WHERE user='" . $usr . "' AND haslo='" . mysql_real_escape_string($_POST['haslo']) . "'");
} else {
print 'Błędne dane wejściowe';
}



http://www.unixwiz.net/techtips/sql-injection.html
http://en.wikipedia.org/wiki/SQL_injection
http://www.phpfreaks.com/phpma[...]ty.database.sql-injection.html
Liczy się treść