SQL Injection

Atak polegający na wstrzyknięciu złośliwego kodu SQL przez pola formularza, by manipulować bazą danych. Może prowadzić do wycieku lub usunięcia danych.

SQL Injection (SQLi) to podatność, w której atakujący wstrzykuje własny fragment kodu SQL do zapytania, jakie aplikacja wysyła do bazy danych. Dzieje się tak, gdy dane od użytkownika (np. login, parametr w URL, pole formularza) lądują w zapytaniu jako zwykły tekst, bez separacji od samej komendy. Baza nie odróżnia wtedy „danych” od „instrukcji” i posłusznie wykonuje to, co podrzucił napastnik — od wyciągnięcia całej tabeli z hasłami po skasowanie rekordów.

Jak to działa

Sednem problemu jest sklejanie zapytań ze stringów. Wyobraź sobie logowanie, gdzie aplikacja buduje zapytanie tak: SELECT * FROM users WHERE login = '$login' AND pass = '$pass'. Jeśli w pole loginu wpiszesz admin' --, zapytanie zmienia się w SELECT * FROM users WHERE login = 'admin' --' AND pass = '...'. Dwa myślniki to komentarz w SQL, więc warunek sprawdzający hasło zostaje wycięty — logujesz się jako admin bez znajomości hasła.

To samo można rozwinąć do groźniejszych technik: UNION-based (doklejasz UNION SELECT, by wyciągnąć dane z innych tabel), blind SQLi (baza nie zwraca błędów, więc wnioskujesz po zachowaniu aplikacji albo czasie odpowiedzi przy SLEEP()), aż po wykonywanie poleceń systemowych przez funkcje typu xp_cmdshell.

Przykład z praktyki

Standardowym narzędziem do wykrywania i eksploatacji jest sqlmap. Test sprowadza się do jednej komendy: sqlmap -u "https://example.com/produkt?id=1" --dbs. Narzędzie samo sprawdza, czy parametr id jest podatny, rozpozna silnik bazy (MySQL, PostgreSQL, MSSQL) i — jeśli jest dziura — wylistuje dostępne bazy danych. To samo SQLi widnieje od lat w czołówce OWASP Top 10 (w wydaniu z 2021 r. w szerszej kategorii „Injection”).

Częste błędy i mity

Mit numer jeden: „escapowanie cudzysłowów wystarczy”. Nie wystarczy — łatwo o lukę przy liczbach, nazwach kolumn czy różnych kodowaniach. Skuteczna obrona to prepared statements (zapytania parametryzowane), gdzie dane idą osobnym kanałem niż komenda. W PHP masz to w PDO, w Javie w PreparedStatement, ORM-y typu Hibernate czy Eloquent robią to domyślnie.

Drugi mit: „mamy ORM, więc jesteśmy bezpieczni”. ORM pomaga, ale w momencie gdy wrzucisz do niego surowy fragment SQL (raw query) ze sklejonym stringiem — dziura wraca. Nie ufaj też walidacji tylko po stronie frontendu; ją obchodzi się banalnie. Waliduj na backendzie i trzymaj zasadę najmniejszych uprawnień konta bazodanowego.

Pojęcia powiązane

Warto zestawić SQLi z: prepared statements, OWASP Top 10, XSS (inny rodzaj wstrzyknięcia, po stronie przeglądarki), input validation, sanityzacja danych oraz WAF (Web Application Firewall) jako dodatkowa warstwa, nigdy zamiast parametryzacji.