Injection ist seit über 20 Jahren eine der häufigsten Schwachstellen-Klassen — und die OWASP Top 10 führen sie konstant unter den ersten fünf. Das gemeinsame Muster ist immer das gleiche: User-Input wird ungeschützt in einen Interpreter gegeben, der ihn als Code ausführt. SQL-Datenbank, OS-Shell, LDAP-Server, XML-Parser, HTTP-Header-Parser — alle haben ihre eigene Spielart. Dieser Artikel zeigt das gemeinsame Modell, die typischen Klassen und die einzige strukturelle Lösung: parametrierte Schnittstellen.
Das gemeinsame Muster
Jede Injection-Klasse folgt demselben dreistufigen Ablauf:
- Anwendung baut einen String aus Anwendungs-Code und User-Input.
- Anwendung übergibt den String an einen Interpreter (Datenbank, Shell, LDAP, etc.).
- Interpreter unterscheidet nicht zwischen Code und Daten — er führt den ganzen String aus.
Klassisches SQL-Injection-Beispiel:
// Schadhaft
const query = `SELECT * FROM users WHERE username = '${userInput}'`;
db.execute(query);Wenn userInput den Wert admin' OR '1'='1 hat, wird der String zu:
SELECT * FROM users WHERE username = 'admin' OR '1'='1'Die SQL-Engine sieht: gültiges Statement. OR '1'='1' ist immer wahr. Alle Zeilen werden zurückgegeben — Auth-Bypass.
Klassisches Command-Injection:
# Schadhaft
import os
os.system(f"ping {user_host}")Mit user_host = "google.com; rm -rf /" startet Shell zwei Befehle. RCE.
Pattern erkennbar: in beiden Fällen wird ein Daten-String textuell in einen Code-String eingebettet. Der Interpreter sieht keinen Unterschied zwischen vom Entwickler vorgegebenem Code und vom Nutzer eingeschmugfeltem Code.
Die strukturelle Antwort: Parametrierung
Die einzige zuverlässige Lösung ist eine fundamentale Trennung von Code und Daten auf API-Ebene. Statt der Interpreter einen fertigen String zu geben, übergibt man separat Code-Schablone und Datenwerte.
Beispiel SQL — Prepared Statements:
// Sicher: Code-Schablone und Daten getrennt
const query = 'SELECT * FROM users WHERE username = ?';
db.execute(query, [userInput]);Was passiert: Die Datenbank parst die Schablone einmal, kennt die Struktur (WHERE username = ?), und behandelt den Datenwert (userInput) als reinen String-Parameter — egal welche Sonderzeichen er enthält. admin' OR '1'='1 ist dann einfach der gesuchte Username, kein injizierter SQL-Code.
Beispiel Command — argv-Form:
# Sicher: argv-Liste statt String-Konkatenation
import subprocess
subprocess.run(["ping", "-c", "1", user_host], shell=False)Hier geht der user_host als separates Argument an ping. Wenn er Semikolons oder Pipes enthält, sind sie Teil des Hostnamens, nicht ein neuer Befehl.
Das Muster ist universell:
- SQL → Prepared Statements / Parameterized Queries.
- LDAP → Parameterized LDAP-Search-Filter mit Escape-Funktion.
- XPath → Parameterized XPath-Query.
- Shell →
execve-Syscall mit argv-Liste stattsystem()mit String. - Mongo → Object-basierte Queries statt String-Concat.
Wer dieses Muster verinnerlicht, hat 90 Prozent aller Injection-Klassen strukturell verhindert.
Die wichtigsten Injection-Klassen
| Klasse | Interpreter | Vertieft in |
|---|---|---|
| SQL-Injection | SQL-Datenbank (Postgres, MySQL, SQLite, MSSQL, Oracle) | sql-injection |
| NoSQL-Injection | MongoDB, CouchDB, Redis | nosql-injection |
| Command Injection | OS-Shell (bash, cmd.exe, PowerShell) | command-injection |
| LDAP-Injection | LDAP-Server (Active Directory, OpenLDAP) | ldap-und-xpath-injection |
| XPath-Injection | XML-Parser | ldap-und-xpath-injection |
| CRLF-Injection | HTTP-Header-Parser, Log-Parser, Mail-Server | crlf-injection-und-log-injection |
| Path Traversal | Dateisystem-API | file-upload-und-pfad-traversal |
| XSS | Browser (HTML/JS-Parser) | Kap 11 |
| Template Injection (SSTI) | Template-Engine (Jinja, Twig, ERB) | template-injection (Kap 11) |
| Header-Injection | HTTP-Server-Parser | crlf-injection-und-log-injection |
Plus verwandte Klassen, die in eigenen Kapiteln behandelt werden:
- XXE-Injection (XML External Entities) → Kap 10.
- SSRF (Server-Side Request Forgery) → Kap 18.
- Prototype Pollution → Kap 10.
Was Eingabe-Validierung (nicht) leistet
Ein verbreiteter Irrweg: „Wir filtern gefährliche Zeichen, dann brauchen wir keine Parametrierung."
Warum das scheitert:
- Filter sind unvollständig. Es gibt viele Wege, Sonderzeichen zu maskieren, zu kodieren, zu verschachteln. Jeder Filter hat Bypasses.
- Filter sind kontext-spezifisch. Ein Filter, der SQL schützt, kann LDAP nicht schützen — andere Sonderzeichen.
- Filter werden Legacy. Filter-Code lebt jahrelang, Datenformate ändern sich.
- Filter bricht legitime Eingaben. Wer alle Apostrophe blockt, blockt auch
O'Brienals Nachnamen.
Was Eingabe-Validierung sinnvoll leistet:
- Datentyp-Validierung — ist das eine Zahl, eine Mail-Adresse, eine UUID?
- Bereichsvalidierung — ist die Zahl positiv, im erwarteten Bereich?
- Format-Validierung — entspricht der String einer erlaubten Struktur?
- Allowlist für Enum-Werte — ist
statuseiner vonpending,active,done?
Eingabe-Validierung ist die erste Schutz-Schicht. Parametrierung ist die strukturelle Schicht. Beide sind nötig — keine ersetzt die andere.
Defense-in-Depth gegen Injection
Eine reife Verteidigung kombiniert mehrere Schichten:
1. Parametrierte Schnittstellen (siehe oben) — strukturelle Trennung von Code und Daten.
2. Eingabe-Validierung — Schema-Validierung mit Allowlist (Zod, Joi, Pydantic, JSON-Schema).
3. Least Privilege im Backend — der Datenbank-User der App hat nur die Rechte, die er braucht. Kein DROP TABLE von einem Login-Endpoint. Vertieft in risiko-und-defense-in-depth.
4. Output-Encoding — falls Werte zurück in HTML/JS/etc. fließen (XSS-Schutz, Kap 11).
5. Logging und Anomalie-Detection — ungewöhnliche Query-Patterns (OR 1=1, sehr lange Strings, ungewöhnliche Zeichen) als Alert.
6. WAF als Reverse-Proxy-Schicht — fängt Standard-Injection-Payloads ab; kein Ersatz für saubere Anwendungs-Architektur.
7. ORM und Query-Builder — viele Frameworks erzwingen Parametrierung als Default. Mehr in sql-injection-orm-fallen.
OWASP-Einordnung
In der OWASP Top 10 2021/2025 ist Injection als A03 geführt. Konsolidiert mit XSS (vorher eigener Punkt) — beides folgt demselben Muster.
In der OWASP API Top 10 2023 ist Injection nicht als eigener Punkt, aber in mehreren Sub-Klassen vertreten — vor allem in Unrestricted Resource Consumption (DoS durch SQL-Injection) und Server-Side Request Forgery.
In der CWE Top 25 sind die wichtigsten Injection-CWEs konsequent in den ersten zehn:
- CWE-79 — XSS.
- CWE-89 — SQL-Injection.
- CWE-77 — Command-Injection.
- CWE-94 — Code-Injection.
- CWE-78 — OS-Command-Injection.
Injection ist eine strukturelle Klasse, die nicht verschwindet — sie wandert nur zwischen Subkategorien.
Warum die Klasse hartnäckig bleibt
Trotz 20 Jahren Aufklärung sind Injection-Bugs in jedem Pentest-Bericht zu finden. Vier Gründe:
- Legacy-Code — Anwendungen aus den 2000ern haben oft string-konkatenierte SQL-Queries. Refactoring ist teuer, Tests sind dünn, Fixes werden verschoben.
- Edge-Cases in ORM-Setups — moderne ORMs parametrieren standardmäßig, aber Raw-Queries, dynamische Spaltennamen und
ORDER BY-Klauseln sind klassische Fallen (siehe sql-injection-orm-fallen). - Shell-Calls aus Bequemlichkeit — eine
os.system("convert image.jpg out.png")-Zeile ist schneller geschrieben als ein sauberer subprocess-Aufruf. Wennimage.jpgaus User-Upload kommt, ist Command-Injection da. - Übersehene Sub-Interpreter — Anwendungen nutzen oft Dutzende kleiner Interpreter (regex, Mail-Header, Cron, Workflow-DSLs, Plugin-Konfig). Jeder davon ist eine Injection-Stelle.
In der Praxis hilft systematisches Code-Review nach Sinks — automatisch (Semgrep, CodeQL) plus manuell. Die Sink-Liste ist überraschend kompakt; wer sie kennt, findet die meisten Bugs.
Interessantes
Der Bobby-Tables-Cartoon
Der xkcd-Comic „Exploits of a Mom" (Randall Munroe, 2007) hat SQL-Injection einer ganzen Generation von Entwickler:innen klar gemacht — die Mutter eines Schülers namens „Robert'); DROP TABLE Students;--" lässt den Schul-Computer alle Schüler-Datensätze löschen. Inzwischen Internet-Kultur-Standard.
Equifax 2017 — Apache Struts Injection mit 147 Millionen Datensätzen
Eine OGNL-Injection in Apache Struts2 (CVE-2017-5638) führte 2017 zum Equifax-Datenleck mit 147 Millionen Kreditdaten — einer der größten Datenlecks der US-Geschichte. Der Patch war zum Vorfallszeitpunkt seit zwei Monaten verfügbar. Lehre: Patch-Disziplin ist Teil der Injection-Verteidigung.
sqlmap als Standard-Test-Tool
sqlmap ist seit 2006 das Standard-Tool für automatisierte SQL-Injection-Tests. Erkennt Klassen, detektiert Database-Type, eskaliert zu Datenexfiltration. Pentest-Standard; Bug-Bounty-Hunting-Pflicht-Werkzeug.
Injection im Postgres-Stack-Overflow-Vorfall 2024
Ein Stack-Overflow-Plugin in einer 2024er CVE konnte über manipulierte SQL-Funktions-Aufrufe RCE im Datenbank-Server auslösen. Plus: einige Postgres-Extensions hatten direkte Code-Execution-Klassen (CVE-2024-…). Lehre: auch innerhalb der „sicheren Parametrierung" können Stored Procedures und Funktionen Injection-Vektoren haben.
Eingabe-Validation an der Boundary, Parametrierung im Code
Eine bewährte Praxis: Schema-Validation an der API-Grenze (was kommt rein?), und Parametrierung bei jedem Interpreter-Aufruf im Code. Beide Schichten gleichzeitig. Eine ohne die andere lässt Lücken.
Stored Procedures sind nicht automatisch sicher
Klassisches Mythos: „Wir nutzen nur Stored Procedures, also kein SQL-Injection." Falsch. Stored Procedures können selbst dynamisches SQL bauen (z. B. mit EXEC(@sql) in MSSQL). Wenn Parameter ungesichert in das dynamische SQL fließen, ist Injection drin. Parametrierung gilt auch innerhalb der Stored Procedure.
Second-Order-Injection als verstecktes Risiko
Ein Wert wird sicher in die Datenbank geschrieben — aber später aus der DB gelesen und unparametriert in eine andere Query eingebaut. Klassisches Pattern: User-Eingabe im Profil speichern, dann später für Suche oder Reports nutzen. Daten-Quelle macht keinen Unterschied — auch DB-Daten gehören parametriert.
Weiterführende Ressourcen
Externe Quellen
- OWASP Top 10 — A03 Injection
- OWASP Injection Prevention Cheat Sheet
- CWE Top 25
- PortSwigger Web Security Academy — Injection
- xkcd 327 — Exploits of a Mom
- sqlmap
- Semgrep Injection Rules