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:

  1. Anwendung baut einen String aus Anwendungs-Code und User-Input.
  2. Anwendung übergibt den String an einen Interpreter (Datenbank, Shell, LDAP, etc.).
  3. Interpreter unterscheidet nicht zwischen Code und Daten — er führt den ganzen String aus.

Klassisches SQL-Injection-Beispiel:

JavaScript sql-injection-basic.js
// 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:

SQL sql-injected.sql
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:

Python command-injection-basic.py
# 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:

JavaScript sql-parametrized.js
// 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:

Python command-parametrized.py
# 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 statt system() 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

KlasseInterpreterVertieft in
SQL-InjectionSQL-Datenbank (Postgres, MySQL, SQLite, MSSQL, Oracle)sql-injection
NoSQL-InjectionMongoDB, CouchDB, Redisnosql-injection
Command InjectionOS-Shell (bash, cmd.exe, PowerShell)command-injection
LDAP-InjectionLDAP-Server (Active Directory, OpenLDAP)ldap-und-xpath-injection
XPath-InjectionXML-Parserldap-und-xpath-injection
CRLF-InjectionHTTP-Header-Parser, Log-Parser, Mail-Servercrlf-injection-und-log-injection
Path TraversalDateisystem-APIfile-upload-und-pfad-traversal
XSSBrowser (HTML/JS-Parser)Kap 11
Template Injection (SSTI)Template-Engine (Jinja, Twig, ERB)template-injection (Kap 11)
Header-InjectionHTTP-Server-Parsercrlf-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 PollutionKap 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'Brien als 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 status einer von pending, 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. Wenn image.jpg aus 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

/ Weiter

Zurück zu Injection (SQL/NoSQL/Cmd)

Zur Übersicht