SQL injection
| Po angielsku | SQL injection |
|---|---|
| Którą formą pisać | po angielsku Polski odpowiednik istnieje, ale w praktyce nikt tak nie pisze. Zostaw angielski, polski trzymaj jako synonim. |
| Inne formy | wstrzyknięcie SQL · wstrzyknięcie zapytania SQL · błędy wstrzyknięcia |
| Kategoria | Podatności i klasy błędów |
SQL injection to podatność, która pozwala wpleść własne polecenia w zapytanie do bazy danych i odczytać, zmienić lub usunąć dane, do których atakujący nie ma prawa. MITRE opisuje ją jako sytuację, w której program buduje całe polecenie SQL lub jego część z danych pochodzących z zewnątrz, ale nie neutralizuje znaków specjalnych, które mogą zmienić sens tego polecenia [1]. OWASP definiuje atak jako wstawienie, czyli „wstrzyknięcie”, zapytania SQL przez dane wejściowe przesłane od klienta do aplikacji [2]. W zestawieniu CWE Top 25 za 2025 rok słabość CWE-89 zajęła drugie miejsce [4].
Jak działa
Aplikacja internetowa często składa zapytanie do bazy z dwóch części: stałego szablonu napisanego przez programistę i wartości podanej przez użytkownika, na przykład numeru wpisu z adresu URL. Jeśli wartość zostanie wklejona do tekstu zapytania bez przygotowania, baza nie odróżni danych od kodu. Sekurak opisuje to tak, że atakujący wstrzykuje do aplikacji nieautoryzowany fragment zapytania SQL, a przyczyną jest brak odpowiedniej walidacji parametru przekazanego przez użytkownika [7].
Przebieg ataku na podatny parametr pokazuje schemat poniżej.
Mechanizm widać na przykładzie w PHP z klasą wpdb WordPressa. Pierwsze zapytanie jest podatne, drugie przekazuje wartość jako parametr.
// podatne: wartość wklejona do tekstu zapytania
$wpdb->get_results( "SELECT * FROM {$wpdb->posts} WHERE ID = " . $_GET['id'] );
// bezpieczne: placeholder %d i osobny argument
$wpdb->get_results( $wpdb->prepare(
"SELECT * FROM {$wpdb->posts} WHERE ID = %d",
$_GET['id']
) );
Odmiany
Odmiany różnią się tym, jak atakujący dowiaduje się o wyniku wstrzykniętego zapytania. PortSwigger zaznacza, że wiele przypadków SQL injection to podatności „ślepe”: aplikacja nie zwraca w odpowiedzi ani wyników zapytania, ani szczegółów błędów bazy [8].
| Odmiana | Jak widać wynik | Uwagi |
|---|---|---|
| Z bezpośrednim wynikiem | dane z innych tabel dołączone do odpowiedzi, np. przez UNION [8] | wynik widać od razu |
| blind SQL injection | aplikacja nie zwraca wyniku ani błędów; wniosek z różnicy odpowiedzi lub opóźnienia [8] | także przez połączenia poza pasmem [8] |
| Drugiego rzędu | dane zapisane w bazie, użyte później w niebezpiecznym zapytaniu [8] | programista ufa danym już zapisanym [8] |
Ładunek może trafić do aplikacji dowolnym kanałem: parametrem adresu, polem formularza, nagłówkiem HTTP albo ciasteczkiem. Liczy się to, czy wartość zostanie potem wklejona do tekstu zapytania.
W WordPressie
WordPress komunikuje się z bazą MySQL lub MariaDB przez obiekt $wpdb. Metoda wpdb::prepare() przygotowuje zapytanie do bezpiecznego wykonania w składni podobnej do sprintf(), z symbolami zastępczymi, które są poprawnie zabezpieczane i ujmowane w cudzysłowy [5]. Obsługuje symbole %d dla liczb całkowitych, %f dla liczb zmiennoprzecinkowych, %s dla tekstu oraz %i dla nazw tabel i kolumn; ten ostatni dodano w WordPressie 6.2.0 [5]. Dokumentacja zastrzega, że symboli zastępczych nie wolno ujmować w cudzysłowy w tekście zapytania i że każdy z nich musi mieć odpowiadający argument [5]. Przy zapytaniach LIKE znak procentu trzeba przekazać przez argument, a samą wartość przepuścić przez wpdb::esc_like() [5].
Podatność powstaje tam, gdzie wtyczka albo motyw buduje zapytanie ręcznie i dokleja do niego dane z żądania z pominięciem prepare(); zob. podatność we wtyczce. Typowe miejsca to własne tabele wtyczek, filtry wyszukiwania i punkty AJAX przyjmujące parametry sortowania. Zmieniony prefiks tabel nie usuwa podatności, a jedynie utrudnia zgadywanie nazw tabel.
Zagrożenia i skutki
MITRE wymienia jako skutki wykonanie nieautoryzowanego kodu lub poleceń, odczyt danych aplikacji, przejęcie uprawnień lub tożsamości, obejście mechanizmów ochrony oraz modyfikację danych [1]. OWASP dodaje, że atak może pozwolić na podszycie się pod innego użytkownika, manipulację danymi, pełne ujawnienie wszystkich danych w systemie, ich zniszczenie, a nawet przejęcie roli administratora serwera bazy [2].
Na stronie WordPress oznacza to przede wszystkim:
- Wyciek danych klientów, zamówień i skrótów haseł z tabeli użytkowników.
- Obejście uwierzytelniania, gdy zapytanie sprawdza login i hasło.
- Utworzenie nieautoryzowanego konta administratora przez dopisanie wiersza do bazy.
- Wstawienie złośliwego kodu do treści wpisów, co łączy SQL injection z XSS.
Jak się bronić
OWASP jako główne zabezpieczenia wymienia zapytania przygotowane z parametrami, poprawnie zbudowane procedury składowane i walidację wejścia z listą dozwolonych wartości [3]. Ręczne zabezpieczanie znaków w całym wejściu użytkownika uznaje za podejście kruche i zdecydowanie odradzane [3]. W WordPressie odpowiednikiem zapytania parametryzowanego jest wpdb::prepare().
Dodatkowe warstwy to:
- Sanityzacja danych wejściowych i rzutowanie typów, na przykład numer wpisu jako liczba całkowita.
- Zasada najmniejszych uprawnień dla konta bazy. OWASP zaleca ograniczenie uprawnień każdego konta bazodanowego i przestrzega przed nadawaniem kontom aplikacji uprawnień administratora bazy [3].
- Zapora aplikacyjna, czyli WAF, którą MITRE wymienia jako jedną z warstw ochrony [1]. Nie zastępuje ona poprawnego kodu.
Historia i przykłady
SQL injection należy do najstarszych i najlepiej opisanych klas błędów. Sekurak w 2013 roku zwracał uwagę, że błąd ten należał wtedy do pierwszej kategorii, A1, w zestawieniu OWASP Top 10 [7]. W klasyfikacji CWE ma numer 89 [1].
W WordPressie głośnym przypadkiem była funkcja $wpdb->prepare(). 31 października 2017 roku WordPress wydał wersję 4.8.3, bo w pewnych warunkach funkcja ta mogła tworzyć nieoczekiwane i niebezpieczne zapytania prowadzące do SQL injection [6]. Błąd zgłosił Anthony Ferrara [6]. Według ogłoszenia sam rdzeń nie był bezpośrednio podatny, ale poprawka utwardzała funkcję, by wtyczki i motywy nie tworzyły luki przypadkiem; zmieniło się też działanie funkcji esc_sql() [6].
Przypisy
8- [1] CWE-89: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection') · MITRE
- [2] SQL Injection · OWASP
- [3] SQL Injection Prevention Cheat Sheet · OWASP
- [4] 2025 CWE Top 25 Most Dangerous Software Weaknesses · MITRE
- [5] wpdb::prepare() — Class Method · WordPress.org
- [6] WordPress 4.8.3 Security Release · WordPress.org
- [7] Czym jest SQL injection? · Sekurak
- [8] SQL injection — Web Security Academy · PortSwigger
Hasła w tym artykule
14Linkują tutaj
42- podatność
- CVE
- OWASP Top 10
- ładunek
- CWE
- escapowanie
- fałszywy alarm
- podatność we wtyczce
- WAF
- bug bounty
- prefiks tabel
- łamanie haseł
- CVSS
- sanityzacja danych wejściowych
- utwardzanie pliku wp-config.php
- wstrzyknięcie poleceń (command injection)
- zapytanie parametryzowane
- podatność wykorzystywana bez uwierzytelnienia
- security through obscurity
- tryb debugowania na produkcji
- ModSecurity
- PHP object injection
- blind SQL injection
- host header injection
- klucze bezpieczeństwa i sole
- CSV injection
- ujawnienie informacji
- fałszywa CAPTCHA
- clickjacking
- naruszenie ochrony danych osobowych
- zapora sieciowa
- stalkerware
- prompt injection
- OAuth 2.0
- skanowanie podatności
- test penetracyjny
- pieprz
- wyciek danych
- system prompt leakage
- vibe coding
- infrastruktura krytyczna
- WPCS