SQL Injection (z ang., dosłownie zastrzyk SQL) – luka w zabezpieczeniach aplikacji internetowych polegająca na nieodpowiednim filtrowaniu albo niedostatecznym typowaniu oraz późniejszym wykonaniu danych przesyłanych w postaci zapytań SQL do bazy danych. Podatne są na niego systemy złożone z warstwy programistycznej (przykładowo skrypt w PHP, ASP, JSP itp.) dynamicznie generującej zapytania do bazy danych (MySQL, PostgreSQL itp.). Wynika on zwykle z braku doświadczenia albo wyobraźni programisty.
Formy ataku SQL Injection
Niedostateczne filtrowanie danych
Ten typ ataków ma za podstawę na nieodpowiednim filtrowaniu znaków ucieczki z danych wejściowych, co dopuszcza na przekazanie dodatkowych parametrów do zapytania.
Poniższy kod prezentuje ten problem (PHP):
$q = mysql_query("SELECT * FROM uzytkownicy WHERE uzytkownik = '$uzytkownik'");
Gdy użytkownik przekaże jako $uzytkownik wartość „kowalski”, całe zapytanie przyjmie postać:
SELECT * FROM uzytkownicy WHERE uzytkownik = 'kowalski'
i będzie spełniało swoją funkcję. Jednak kiedy złośliwy użytkownik przekaże wartość „x' OR '1'='1”, to całe zapytanie będzie wyglądało:
SELECT * FROM uzytkownicy WHERE uzytkownik = 'x' OR '1'='1'
przez co pobierze z bazy danych wszystkie rekordy zamiast jednego wybranego.
Teoretycznie w ten sposób da się przekazać każde zapytanie SQL, włącznie z wykonaniem kilku zapytań naraz. Jeżeli w powyższym przykładzie użytkownik przekaże „x';DROP TABLE uzytkownicy; SELECT '1”, to całe zapytanie przybierze postać:
SELECT * FROM uzytkownicy WHERE uzytkownik = 'x';DROP TABLE uzytkownicy; SELECT '1'
co zaowocuje usunięciem tabeli „uzytkownicy”. W praktyce może to być niemożliwe, bo biblioteka używana do połączenia np. z MySQL w PHP nie dopuszcza na wykonywanie dwóch zapytań jednocześnie.
Korzystając z ataku typu SQL Injection da się także przeprowadzić atak typu DoS (odmowy usługi):
x' AND BENCHMARK(9999999,BENCHMARK(999999,BENCHMARK(999999,MD5(NOW()))))=0 OR '1'='1
W tym przypadku serwer spróbuje obliczyć skrót MD5 dla aktualnego czasu
(w zaokrągleniu trylion) razy.
„Ślepy” atak
O „ślepym” ataku (ang. Blind SQL Injection) powiada się w przypadku wykonywania ataku typu SQL Injection na stronie, która nie wyświetla komunikatów błędów. W tym przypadku badać da się zmiany na stronie, przykładowo:
SELECT * FROM uzytkownicy WHERE uzytkownik='x' AND 1=2;
Powyższe zapytanie winno nic nie zwrócić. Inaczej w przypadku wykonania poniższego zapytania:
SELECT * FROM uzytkownicy WHERE uzytkownik='x' OR 1=1;
Powyższe zapytanie winno stale zwrócić jakikolwiek wynik, bowiem 1 jest równe 1. Badając zmiany zachodzące na stronie da się stwierdzić czy w danym miejscu da się dokonać ataku.
Błędy w serwerze SQL
Czasami błędy umożliwiające atak są w samym serwerze SQL, jak było w przypadku funkcji real_escape_chars() z MySQL.
Zabezpieczanie przed atakiem
Zabezpieczanie na poziomie aplikacji
Podstawowym sposobem zabezpieczania przed SQL injection jest niedopuszczenie do nieuprawnionej zmiany wykonywanego zapytania.
W PHP da się to zrobić, poprzez wykonanie na każdym tekstowym parametrze wykorzystywanym do budowy zapytania wbudowanej funkcji addslashes(), która dodaje backslash przed znakami, takimi jak ', " czy \, dzięki czemu znaki te nie są traktowane jak znaki specjalne. Dostępne są także funkcje specyficzne dla poszczególnych silników, takie jak np. oferowana przez serwer MySQL mysql_real_escape_string(). Jeśli wczytując dane z formularza programista oczekuje wartości liczbowych, może korzystać z funkcji is_numeric(zmienna), która sprawdza czy zmienna jest wartością numeryczną. Po sprawdzeniu zmiennej oraz upewnieniu się, iż jest liczbą, da się bezpiecznie użyć zmiennej w zapytaniu SQL.
Analogicznie do addslashes(), w perlowym DBI istnieje metoda DBI::quote, która, analogicznie jak addslashes() z PHP dodaje znaki backslash przed potencjalnie niebezpiecznymi znakami. Przykład (zakładając, że $sql jest referencją do obiektu DBI):
$query = $sql->prepare("SELECT * FROM uzytkownicy where name = " . $sql->quote($uzytkownik));
Bezpieczniejszą techniką, niż wyżej wymienione odpowiednie przygotowanie parametrów jest użycie mechanizmu tzw. „zaślepek”, gdzie zmienne nie są używane bezpośrednio do tworzenia zapytania, a odpowiednie dane dołączane są do zapytania w momencie jego wykonania (czy to poprzez wykorzystanie API danego silnika, czy też w ramach warstwy aplikacji poprzez odpowiednie zacytowanie wszystkich parametrów). Przykład w Perl DBI:
$query = $sql->prepare("SELECT * FROM users WHERE name = ?");
$query->execute($user_name);
Jeżeli parametr zapytania ma być wartością liczbową da się go po prostu rzutować na typ liczbowy albo użyć funkcji konwertujących z ciągu znaków na wartość liczbową.
Techniką utrudniającą wykorzystanie istniejących luk jest zastosowanie paradygmatu security through obscurity poprzez wyłączenie wyświetlania komunikatów o błędach. Nie uniemożliwi to ataku, lecz może spowodować, że trudniejsze będzie wykrycie oraz późniejsze wykorzystanie luki.
Zabezpieczenie na poziomie bazy danych
Istnieją także metody zabezpieczenia przed skutkami wykonania błędnych zapytań, które mimo wszystko dostaną się do bazy.
Udostępnienie użytkownikowi bazy tylko niezbędnych uprawnień nie da całkowitej ochrony, jednak pozwoli na minimalizację szkód. Dla przykładu – niewiele aplikacji potrzebuje uprawnienia do kasowania tabel z bazy danych. Podobny efekt – czyli zmniejszenie możliwości atakującego – uzyskać da się wyłączając niepotrzebną funkcjonalność na poziomie samego silnika.
Pomocą potrafią służyć także procedury składowane, dzięki którym zapytanie budowane jest po stronie bazy danych oraz aplikacja nie ma bezpośredniego wpływu na jego postać. Chociaż oraz w tym przypadku skonstruowanie ataku nie jest niemożliwe.
Eliminację możliwości wstrzyknięcia kodu SQL, da się uzyskać poprzez całkowite wyłączenie możliwości podawania parametrów jako części zapytania. Jest to działanie analogiczne do mechanizmu zaślepek po stronie aplikacji, jednak tym razem zastosowane w samym silniku. Nie jest to jednak ogólnie dostępna cecha systemów zarządzania bazami. W chwili obecnej, możliwość taką daje silnik H2.
Zabezpieczanie na poziomie serwera aplikacji/www
Jest możliwość instalacji dodatkowych modułów do serwera warstwy aplikacyjnej (np. mod_security do serwera Apache) filtrujących wg zdefiniowanych reguł przychodzące żądania oraz blokujących te potencjalnie groźne. Reguły pozwalają na wychwycenie typowych uniwersalnych ataków albo znanych luk w popularnych aplikacjach. Wadą rozwiązania jest możliwość zablokowania także pożądanych wywołań (np. w aplikacji do zarządzania bazą danych).
Linki zewnętrzne