💉 Zaawansowane techniki SQL Injection (defense‑first)

Jak je rozpoznać, jak zablokować i jak bezpiecznie trenować

Zaawansowane techniki SQL Injection (defense‑first)

🎯 Wprowadzenie i odpowiedzialne użycie

SQL Injection (SQLi) to nadal jedna z najgroźniejszych podatności aplikacji webowych. Ten przewodnik przedstawia techniki SQLi w ujęciu defense‑first — najpierw jak je wykryć i zablokować, a dopiero potem, gated, przykłady payloadów do laboratoriów.

⚠️ Aspekt prawny i etyczny:
  • Używaj wyłącznie w autoryzowanych testach z pisemną zgodą i jasno zdefiniowanym zakresem.
  • Nie uruchamiaj payloadów w systemach produkcyjnych bez uzgodnionych okien serwisowych.
  • Wszystkie sekcje z wrażliwymi ładunkami są ukryte i odblokowywane świadomie (gating).

🧭 Model zagrożeń i typy SQLi

👁️ Blind / Boolean‑based

Brak błędów w odpowiedzi; wnioskujemy na podstawie różnic w zachowaniu (TRUE/FALSE).

⏱️ Time‑based

Wstrzykiwanie opóźnień czasowych, gdy brak różnic w treści odpowiedzi.

🔗 Union‑based

Łączenie wyników atakującego z właściwym zapytaniem (UNION SELECT).

💥 Error‑based

Wykorzystanie komunikatów błędów DBMS do ekstrakcji informacji.

🔄 Second‑order

Dane złośliwe zapisane wcześniej są użyte później w innym zapytaniu.

🛡️ WAF Evasion

Omijanie filtrów WAF przez encoding, obfuskację i składnię specyficzną dla DBMS.

🔎 Wspólne metody wykrywania

Detekcja (Blue Team):
  • Nagłe wzrosty kodów 500/406/403 oraz długie TTFB (Time To First Byte).
  • W logach WAF/serwera: wzorce typu UNION, SELECT, SLEEP, WAITFOR, nadmiar znaków ' " -- /* */.
  • Anomalie w parametrach: niespodziewane znaki specjalne, nietypowe długości, wielokrotne te same parametry (HPP).
  • Korelacja w SIEM: „krytyczna podatność” + „anomalia logowania/IDS” dla tego samego hosta.
Mitygacja (na poziomie aplikacji/DB):
  • Parametryzacja zapytań (prepared statements) i whitelisty kolumn/sortowania.
  • Role i uprawnienia DB zgodne z zasadą najmniejszych uprawnień.
  • Standaryzacja błędów (brak stack trace dla użytkownika) i centralne logowanie.
  • Testy automatyczne bezpieczeństwa w CI/CD i retesty po poprawkach.

👁️ Blind/Boolean‑based SQLi

Gdy aplikacja nie zwraca błędów i nie wyświetla danych z zapytania, różnice w zachowaniu (np. inne widoki/redirecty) ujawniają TRUE/FALSE.

Detekcja:
  • Wzorce w logach: wartości parametru różniące się pojedynczym znakiem i naprzemiennie skutkujące innymi kodami HTTP.
  • Wzrost liczby żądań binarnego wyszukiwania (ASCII/SUBSTRING/LENGTH) w krótkich oknach czasu.
Mitygacja:
  • Parametryzacja zapytań i logiczne whitelisty dla operatorów.
  • Normalizacja danych wejściowych (canonicalization) przed walidacją.
  • Limit zapytań per użytkownik/źródło + backoff (Rate Limiting).
-- Przykłady payloadów do labu (BOOLEAN / Blind) ' AND 1=1-- ' AND 1=2-- ' AND LENGTH(DATABASE())=8-- ' AND SUBSTRING(DATABASE(),1,1)='t'--

⏰ Time‑based SQLi

Gdy brak różnic w treści odpowiedzi, czas odpowiedzi (opóźnienia) sugeruje wartość logiczną warunku.

Detekcja:
  • Anomalie w rozkładzie czasu odpowiedzi (np. wiele ~5 s lub ~10 s).
  • W logach WAF/DBMS: funkcje SLEEP/WAITFOR/pg_sleep/DBMS_LOCK.SLEEP.
Mitygacja:
  • Prepared statements, bez łączenia ciągów w SQL.
  • WAF z polityką opóźnień adaptacyjnych i regułami dla funkcji czasowych.
  • Timeouty na poziomie aplikacji i DB oraz ograniczenia złożoności zapytań.
-- MySQL ' AND IF(1=1, SLEEP(5), 0)-- -- PostgreSQL '; SELECT CASE WHEN (1=1) THEN pg_sleep(5) ELSE 0 END-- -- SQL Server '; IF (1=1) WAITFOR DELAY '00:00:05'-- -- Oracle ' AND (SELECT CASE WHEN (1=1) THEN DBMS_LOCK.SLEEP(5) ELSE 0 END FROM DUAL)=0--

🔄 Second‑order (stored) SQLi

Dane wstrzyknięte w jednym miejscu są użyte później w innym zapytaniu. Payload i eksploitacja są rozdzielone w czasie.

Detekcja:
  • Mapowanie przepływu danych (data flow) — które pola są zapisywane i gdzie później używane w SQL.
  • Alerty na dynamicznie generowane fragmenty SQL z danymi użytkownika.
Mitygacja:
  • Parametryzacja w każdym miejscu użycia danych (nie tylko przy zapisie).
  • Enkodowanie kontekstowe i walidacja formatu przed użyciem.
-- Scenariusze labowe (second-order) — do ćwiczeń: -- 1) Rejestracja z 'admin'/* → później zapytanie WHERE author='admin'/*' -- 2) Zapisane wyszukiwania → późniejsze buildowanie zapytania z LIKE '%{term}%'

🔗 Union‑based i 💥 Error‑based

Union‑based łączy wyniki z oryginalnym zapytaniem; Error‑based wykorzystuje komunikaty błędów DBMS do ekstrakcji.

Detekcja:
  • W treści żądań/odpowiedzi: UNION, SELECT, GROUP_CONCAT/LISTAGG, FOR XML PATH, EXTRACTVALUE/UPDATEXML.
  • W logach aplikacji: wyjątki SQL, stack trace, powtarzalne błędy konwersji typów.
Mitygacja:
  • Wyłącz „verbose errors” dla użytkowników; loguj szczegóły po stronie serwera.
  • Whitelisting kolumn i typów, ograniczenia długości i znaków w parametrach.
  • Parametryzacja + polityki DB ograniczające funkcje XML/FILE/XP_CMDSHELL (SQL Server).
-- Union-based — ustalanie liczby kolumn (ORDER BY / NULL) ' ORDER BY 3-- ' UNION SELECT null,null,null-- -- Error-based — MySQL (EXTRACTVALUE/UPDATEXML) ' AND EXTRACTVALUE(1, CONCAT(0x3a, database()))--

🛡️ Obejścia WAF: ryzyka i obrona

Obfuskacja, encoding i składnie specyficzne dla DBMS mogą obniżać skuteczność WAF.

Detekcja:
  • WAF: reguły „anomaly scoring” zamiast pojedynczych sygnatur; korelacja z czasem odpowiedzi.
  • SIEM: wykrywanie prób wieloetapowych (różne encodings, mixed‑case, komentarze, HPP).
Mitygacja:
  • Łączenie WAF + RASP + parametryzacja. WAF to warstwa wsparcia, nie jedyna zapora.
  • Reguły specyficzne dla aplikacji (allow‑listy) i sanityzacja na wejściu.
  • Monitoring false‑negatives i regularne testy skuteczności WAF w stagingu.
-- Przykłady labowe obejść (nie używać na produkcji): '/**/UNION/**/SELECT/**/*//**/FROM/**/users-- %27%20UNION%20SELECT%20%2A%20FROM%20users-- ' /*!50000UNION*/ /*!50000SELECT*/ * /*!50000FROM*/ users--

🛠️ Narzędzia: bezpieczne użycie

Narzędzia automatyczne (np. sqlmap) mogą pomóc, ale łatwo przeciążyć aplikację i wygenerować FP/FN.

Zasady operacyjne:
  • Testuj w stagingu/labie; ustal limity i przerwy; dokumentuj parametry skanu.
  • Uzgodnij poziom agresywności (techniques, threads, delay) i okna testowe.
# Ostrożny profil sqlmap (niski wpływ) sqlmap -u "https://target.tld/item.php?id=1" --batch \ --level=1 --risk=1 --random-agent --timeout=15 --retries=1 \ --threads=1 --technique=BEU --exclude-sysdbs
# Przykłady bardziej agresywne (tylko lab/staging) sqlmap -u "https://target.tld/item.php?id=1" --dump --threads=5 --technique=BEUSTQ sqlmap -u "https://target.tld/login.php" --data="user=*&pass=test" --tamper=space2comment,charencode

🛡️ Obrona: wzorce i twardnienie

Prepared statements (PHP, Python, Java)

PDO::ERRMODE_EXCEPTION]); $stmt = $pdo->prepare("SELECT * FROM users WHERE id = ? AND status = ?"); $stmt->execute([$userId, $status]); // Whitelist dla sortowania $allowed = ['id','username','email']; $sort = in_array($_GET['sort'] ?? 'id', $allowed) ? $_GET['sort'] : 'id'; $q = $pdo->query("SELECT id, username, email FROM users ORDER BY $sort"); ?>
# Python (psycopg2) import psycopg2 conn = psycopg2.connect(dsn) cur = conn.cursor() cur.execute("SELECT * FROM users WHERE id = %s AND status = %s", (user_id, status)) rows = cur.fetchall()
/* Java JDBC */ PreparedStatement ps = conn.prepareStatement("SELECT * FROM users WHERE id = ? AND status = ?"); ps.setInt(1, userId); ps.setString(2, status); ResultSet rs = ps.executeQuery();

Hardening bazy danych

-- Zasada najmniejszych uprawnień (MySQL) CREATE USER 'webapp_user'@'app-host' IDENTIFIED BY 'Strong#Pwd!'; GRANT SELECT, INSERT, UPDATE ON app_db.* TO 'webapp_user'@'app-host'; -- Wyłącz nieużywane funkcje SET GLOBAL local_infile = 0; -- SQL Server: wyłącz xp_cmdshell EXEC sp_configure 'show advanced options', 1; RECONFIGURE; EXEC sp_configure 'xp_cmdshell', 0; RECONFIGURE;

Standaryzacja błędów i logowanie

Dobre praktyki:
  • Użytkownik otrzymuje ogólny komunikat; szczegóły trafiają do centralnego logu.
  • Maskuj dane wrażliwe (PII) w logach; definiuj retencję i dostęp.
  • Alerty na wzorce SQLi + korelacja z WAF/IDS.

🧪 Testy automatyczne i KPI

Testy jednostkowe bezpieczeństwa

# Przykładowy test walidacji i parametryzacji def is_valid_username(x: str) -> bool: import re return bool(re.fullmatch(r"[a-zA-Z0-9_]{3,20}", x)) def test_username_validation(): assert is_valid_username("jan_kowalski") assert not is_valid_username("admin'--") assert not is_valid_username("a") # za krótki

KPI programu AppSec

  • MTTR dla podatności krytycznych/wysokich (rolling 30 dni).
  • Recurrence rate (ponowne wystąpienia po „fixed”).
  • Coverage — % endpointów objętych testami/analizą.
  • WAF FN rate — udział prób nieprzechwyconych przez WAF.

📚 Laboratoria i zasoby

  • PortSwigger Web Security Academy — świetne laby SQLi (również advanced).
  • DVWA / bWAPP / Mutillidae — środowiska do ćwiczeń (Docker).
  • OWASP Cheat Sheet Series — SQL Injection Prevention.
  • Książki: „SQL Injection Attacks and Defense”, „The Database Hacker’s Handbook”.
⚖️ Przypomnienie: Payloady odblokowujesz świadomie i używasz wyłącznie w autoryzowanych labach/testach. Za naruszenia prawa odpowiada użytkownik.
📧 Chcesz audyt lub szkolenie? Skontaktuj się ze mną — pomogę zaprojektować testy, zabezpieczenia i procesy, które realnie redukują ryzyko.