SQL Injection: Wie sie funktioniert und wie man sie verhindert
SQL-Injection gehört seit Jahrzehnten zu den meistgenutzten Angriffsvektoren. Sehen Sie, wie ein Angriff Daten extrahiert, und lernen Sie die wirksamen Abwehrmaßnahmen.
Inhaltsverzeichnis
Warum SQL Injection noch immer existiert
SQL Injection wurde erstmals 1998 dokumentiert. Es ist in jeder OWASP Top-10-Liste seit deren Gründung aufgetaucht. Es war für einige der größten Datenpannen der Geschichte verantwortlich — TalkTalk (4 Millionen Datensätze), Heartland Payment Systems (130 Millionen Kartennummern) und unzählige andere.
Der Grund für seine Persistenz ist nicht Komplexität. SQL Injection ist einfach zu verstehen und, entscheidend, einfach zu verhindern. Es persistiert, weil Entwickler Benutzereingaben ohne Nachdenken über die Konsequenzen in SQL-Abfragen konkatenieren, oft unter Zeitdruck und ohne Sicherheitsschulung.
Dieses Tutorial zeigt genau, wie es funktioniert und die spezifischen Techniken, die es eliminieren.
Wie eine SQL-Abfrage normalerweise funktioniert
Betrachte ein Login-Formular. Die Anwendung nimmt einen Benutzernamen und ein Passwort und prüft sie gegen die Datenbank:
SELECT * FROM users WHERE username = 'alice' AND password = 'secretpass';
Wenn die Abfrage eine Zeile zurückgibt, wird der Benutzer authentifiziert. Das ist normales und erwartetes Verhalten.
Die Schwachstelle entsteht, wenn ein Entwickler diese Abfrage durch direkte Konkatenation von Zeichenketten aus Benutzereingaben konstruiert:
# Anfälliger Python-Code
query = "SELECT * FROM users WHERE username = '" + username + "' AND password = '" + password + "';"
Die Annahme ist, dass Benutzer normale Werte eingeben. Angreifer tun das nicht.
Der Angriff: Aus der Zeichenkette ausbrechen
SQL verwendet einfache Anführungszeichen, um Zeichenkettenwerte zu begrenzen. Wenn ein Angreifer einen Benutzernamen mit einem einfachen Anführungszeichen eingibt, kann er aus der vorgesehenen Zeichenkette ausbrechen und eigenes SQL einschleusen.
Eingabe des Angreifers:
- Benutzername:
' OR '1'='1 - Passwort:
beliebig
Resultierende Abfrage:
SELECT * FROM users WHERE username = '' OR '1'='1' AND password = 'beliebig';
Da OR '1'='1' immer wahr ist, gibt diese Abfrage alle Benutzer zurück. Das Login gelingt für den ersten Benutzer in der Datenbank, typischerweise ein Administrator.
Passwortprüfung vollständig umgehen:
- Benutzername:
admin'-- - Das
--ist ein SQL-Kommentar; alles danach wird ignoriert
SELECT * FROM users WHERE username = 'admin'--' AND password = 'beliebig';
-- Wird zu:
SELECT * FROM users WHERE username = 'admin';
Authentifizierung wird umgangen. Das Passwortfeld wird nie geprüft.
Jenseits der Authentifizierung: Daten extrahieren
SQL Injection ist nicht auf Authentifizierungsumgehung beschränkt. Schwerwiegendere Angriffe extrahieren Daten aus der gesamten Datenbank.
UNION-basierte Injection
Der SQL-UNION-Operator kombiniert Ergebnisse zweier SELECT-Anweisungen. Ein Angreifer kann ihn verwenden, um Daten aus anderen Tabellen abzurufen:
-- Ursprüngliche Abfrage
SELECT name, description FROM products WHERE id = 1;
-- Eingeschleust
SELECT name, description FROM products WHERE id = 1
UNION SELECT username, password FROM users--;
Das hängt alle Benutzernamen und Passwörter an die dem Angreifer zurückgegebenen Produktergebnisse an.
Blinde SQL Injection
Viele Anwendungen zeigen Datenbankfehler oder Abfrageergebnisse nicht für Benutzer an. Blinde SQL Injection extrahiert Daten Bit für Bit, indem Wahr/Falsch-Fragen gestellt werden:
-- Ist das erste Zeichen des Admin-Passworts 'a'?
SELECT * FROM users WHERE id = 1 AND SUBSTRING(password, 1, 1) = 'a';
Wenn sich die Seite anders verhält, wenn die Bedingung wahr ist versus falsch, kann der Angreifer die Antwort ableiten. Automatisierte Tools wie sqlmap können ganze Datenbanken durch blinde Injection in Minuten extrahieren.
Out-of-Band und gestapelte Abfragen
Auf einigen Datenbanksystemen können Angreifer:
- Mehrere Anweisungen ausführen (gestapelte Abfragen): Tabellen löschen, Backdoor-Konten erstellen
- Dateien vom Serverdateisystem lesen (
LOAD_FILE()in MySQL) - Dateien auf den Server schreiben (potenziell eine Web-Shell erstellen)
- Netzwerkverbindungen auslösen, um Daten außerhalb des Bandes zu exfiltrieren
SQL Injection bedeutet im schlimmsten Fall vollständige Serverkompromittierung, nicht nur Datenoffenlegung.
Die Abwehrmaßnahmen, die wirklich funktionieren
Abwehr 1: Parametrisierte Abfragen (Prepared Statements)
Dies ist die primäre Abwehr und sie eliminiert SQL Injection, reduziert sie nicht nur.
Mit einer parametrisierten Abfrage werden SQL-Code und Daten getrennt an die Datenbank gesendet. Die Datenbank kompiliert das SQL-Template zuerst und bindet dann die vom Benutzer eingegebenen Werte. Die Werte können niemals als SQL interpretiert werden — sie werden immer als Daten behandelt.
Python mit parametrisierter Abfrage:
# Sicher
cursor.execute(
"SELECT * FROM users WHERE username = %s AND password = %s",
(username, password)
)
Java mit PreparedStatement:
PreparedStatement stmt = conn.prepareStatement(
"SELECT * FROM users WHERE username = ? AND password = ?"
);
stmt.setString(1, username);
stmt.setString(2, password);
Egal was der Benutzer im username-Feld eingibt — einschließlich ' OR '1'='1 — es wird als literaler Zeichenkettenwert behandelt, nicht als SQL. Die Injection ist unmöglich.
Abwehr 2: ORMs und Query Builder
Object-Relational Mapper (ORMs) wie SQLAlchemy, Hibernate, ActiveRecord und Django ORM verwenden intern parametrisierte Abfragen. Ein ORM korrekt zu verwenden verhindert SQL Injection in fast allen Fällen:
# Django ORM — sicher
User.objects.filter(username=username, password=password)
Vorsicht: Die meisten ORMs haben Ausstiegswege für rohes SQL (raw(), execute()), die das Injection-Risiko wieder einführen, wenn Benutzereingaben konkateniert werden. Behandle rohe SQL-Methoden mit der gleichen Sorgfalt wie manuelle Abfragekonstruktion.
Abwehr 3: Stored Procedures
Stored Procedures können sicher sein, wenn sie korrekt implementiert werden — sie müssen intern parametrisierte Eingaben verwenden. Eine Stored Procedure, die intern Zeichenketten konkateniert, ist immer noch anfällig.
Abwehr 4: Prinzip der minimalen Rechte
Das von der Webanwendung verwendete Datenbankkonto sollte nur die benötigten Berechtigungen haben:
- Eine leselastige Anwendung benötigt nur
SELECT - Keine Anwendung sollte als
root,saoderDBAlaufen - Verschiedene Anwendungskomponenten können verschiedene Datenbankkonten mit unterschiedlichen Berechtigungen verwenden
Dies begrenzt die Auswirkungen erfolgreicher Injection: Ein Angreifer, der nur SELECT kann, kann keine Tabellen löschen oder Dateien schreiben.
Abwehr 5: Eingabevalidierung
Validiere, dass Eingaben ihrem erwarteten Format entsprechen:
- Eine Benutzer-ID sollte eine positive ganze Zahl sein — lehne alles andere ab, bevor es die Abfrage erreicht
- Ein Produktname sollte keine SQL-Schlüsselwörter enthalten — erlaubte Zeichen per Allowlist festlegen
Eingabevalidierung ist eine Maßnahme der Defense in Depth, keine primäre Kontrolle. Sie reduziert die Angriffsfläche, sollte aber nicht der einzige Schutz sein.
Abwehr 6: WAF (Web Application Firewall)
Eine WAF kann gängige SQL-Injection-Muster erkennen und blockieren. Sie ist eine zusätzliche Schicht, kein Ersatz für parametrisierte Abfragen. WAFs können durch Verschleierung und Kodierungstricks umgangen werden. Verlasse dich nicht auf sie als einzige Abwehr.
Auf SQL Injection testen
Grundlagen manuelles Testen:
- Gib ein einfaches Anführungszeichen (
') in jedes Eingabefeld ein — Datenbankfehlermeldungen zeigen oft Injection-Punkte an - Versuche
1=1und1=2in numerischen Parametern und vergleiche die Antworten - Versuche
'; SELECT SLEEP(5);--— wenn die Antwort verzögert ist, ist blinde Injection vorhanden
Automatisierte Tools:
- sqlmap — das Standard-Tool für Erkennung und Exploitation (nur gegen Systeme, die du autorisiert bist zu testen)
- Burp Suite — Anfragen abfangen und manipulieren; hat einen SQL-Injection-Scanner in der Pro-Edition
- OWASP ZAP — kostenloser Scanner mit SQL-Injection-Erkennung
Remediation-Checkliste
- Alle Zeichenketten-Konkatenationen in Datenbankabfragen durch parametrisierte Abfragen ersetzen
- Alle rohen SQL-Aufrufe im ORM-Code prüfen
- Datenbankkonten mit minimalen Rechten anwenden
- Datenbankfehlerunterdrückung in der Produktion aktivieren (Fehler enthüllen Schema-Informationen)
- Stored Procedures überprüfen und testen
- WAF-Regeln als zusätzliche Schicht hinzufügen
- sqlmap oder Äquivalent in der Staging-Umgebung vor jedem Release ausführen
SQL Injection hat eine vollständige, gut verstandene Lösung. Es gibt keinen Grund, dass sie in neuem Code auftaucht. Die einzige Hürde ist Bewusstsein und Disziplin während der Entwicklung.