Während die meisten Web-Sicherheits-Themen auf der Anwendungs-Schicht spielen, gibt es eine eigene Klasse von Angriffen, die unter der App auf der HTTP-Protokoll-Ebene stattfinden — zwischen Reverse-Proxy, Load Balancer und Backend-Server. HTTP Request Smuggling und Host-Header-Injection sind die zwei wichtigsten Vertreter. Dieser Artikel ordnet beide Klassen: was sie technisch sind, wie sie reale Angriffe (Cache-Poisoning, Auth-Bypass, Password-Reset-Hijacking) ermöglichen — und welche Härtungs-Patterns sie verhindern.
HTTP Request Smuggling: das Grund-Prinzip
In modernen Web-Architekturen liegt fast immer ein Front-End-Server vor dem Backend — eine Cloudflare, ein Nginx, ein AWS-Load-Balancer, ein ALB. Front-End empfängt HTTP-Anfragen vom Internet und reicht sie an das Backend weiter.
Das funktioniert, solange Front-End und Backend dieselbe HTTP-Interpretation haben. Wenn nicht — wenn beide eine HTTP-Anfrage anders parsen — entsteht Request Smuggling: eine vom Front-End als „eine Anfrage" gesehene Bytes-Folge wird vom Backend als „zwei Anfragen" interpretiert. Die zweite Anfrage ist dem Front-End versteckt und nicht durch dessen Sicherheits-Filter gelaufen.
Die Diskrepanz entsteht meist an Längen-Angaben der HTTP-Anfrage. HTTP/1.1 erlaubt zwei Mechanismen:
Content-Length: N— der Body ist genau N Bytes lang.Transfer-Encoding: chunked— der Body ist in Chunks mit jeweils eigener Längen-Angabe.
Eine Anfrage soll laut Standard nur einen dieser beiden Mechanismen nutzen. Wenn beide gesetzt sind — und Front-End/Backend wählen unterschiedliche —, entsteht Smuggling.
Die Smuggling-Varianten
Drei klassische Varianten (Klassifikation von James Kettle / PortSwigger):
CL.TE — Front-End nutzt Content-Length, Backend nutzt Transfer-Encoding.
POST / HTTP/1.1
Host: example.com
Content-Length: 13
Transfer-Encoding: chunked
0
SMUGGLED- Front-End sieht
Content-Length: 13→ liest 13 Bytes → leitet alles weiter. - Backend sieht
Transfer-Encoding: chunked→ liest bis zum0-Chunk-End → die danach folgenden BytesSMUGGLEDsind für das Backend eine separate, geschmuggelte Anfrage.
TE.CL — umgekehrt.
Front-End versteht Transfer-Encoding, Backend versteht Content-Length. Smuggling-Payload ist anders konstruiert, der Effekt analog.
TE.TE — beide verstehen TE, eines „obfuskiert" weg.
Manche Server akzeptieren Transfer-Encoding: chunked mit kreativer Whitespace- oder Case-Variation als gültig (z. B. Transfer-Encoding : chunked mit Leerzeichen). Andere lehnen es ab. Wenn Front-End und Backend unterschiedlich tolerant sind, kommt es zu Smuggling.
HTTP/2-Downgrade-Smuggling.
Front-End spricht HTTP/2, Backend HTTP/1.1. Front-End wandelt um. Manche HTTP/2-Anfragen lassen sich so konstruieren, dass sie nach Downgrade zwei HTTP/1.1-Anfragen ergeben. Diese Klasse wurde 2021 von James Kettle ausführlich erforscht.
Was Smuggling angreift
Die geschmuggelte zweite Anfrage wird dem nächsten Front-End-Aufruf zugeschrieben. Das hat mehrere böse Konsequenzen:
- Auth-Bypass. Die geschmuggelte Anfrage erbt die Auth-Cookies des nächsten unbeteiligten Nutzers — Angreifer bekommt Zugang zu fremder Session.
- Cache-Poisoning. Geschmuggelte Anfrage lässt das Backend eine manipulierte Antwort zurückgeben, die im Front-End-Cache landet und an alle nachfolgenden Nutzer:innen ausgeliefert wird.
- Information-Disclosure. Die geschmuggelte Anfrage triggert eine Backend-Antwort, die dem nächsten User-Request als Body angehängt wird.
- Backend-Header-Injection. Geschmuggelter Inhalt kann Backend-Header setzen, die Front-End-Filter umgehen.
Reale Vorfälle: James Kettle hat seit 2019 in mehreren PortSwigger-Veröffentlichungen Hunderte realer Smuggling-Bugs bei großen Unternehmen dokumentiert (Bug-Bounty-Berichte mit fünfstelligen Auszahlungen sind nicht selten).
Smuggling verhindern
Die Verteidigung läuft auf zwei Ebenen:
1. Front-End-Backend-Konsistenz. Beide Komponenten müssen dieselbe HTTP-Interpretation haben. Idealerweise: nur eine Längen-Angabe pro Anfrage akzeptieren, alle anderen ablehnen. Front-End und Backend von demselben Hersteller oder zumindest in einer getesteten Kombination verwenden.
2. HTTP/2 End-to-End. HTTP/2 hat eine strikte binäre Frame-Struktur ohne Längen-Doppeldeutigkeiten. Wenn Front-End und Backend HTTP/2 sprechen, ist die klassische CL/TE-Smuggling-Klasse strukturell unmöglich. Aber: Downgrades innerhalb der Kette (HTTP/2 vor → HTTP/1.1 dahinter) bringen das Problem zurück.
Konkrete Patterns:
- Reverse-Proxy normalisieren —
proxy_request_buffering onin Nginx, normalisierte Header. Transfer-Encoding: chunkedmit gleichzeitigemContent-Lengthstrikt ablehnen (RFC 7230 verlangt das).- HTTP/2 mit
h2c-Downgrade-Schutz auf Backend-Seite. - Front-End-Konfiguration:
proxy_http_version 1.1und konsistente Connection-Behandlung.
Werkzeuge zum Testen:
- Burp Suite Pro — eingebauter Smuggling-Scanner („HTTP Request Smuggler"-Plugin von Albinowax/Kettle).
- Smuggler.py — Open-Source-Test-Tool für CL/TE-Varianten.
Host-Header-Injection: das andere HTTP-Klassen-Angriff
Eine ganz andere HTTP-Schicht-Schwachstelle, mit ähnlichem Hebel: Anwendung nutzt den Host:-Header der HTTP-Anfrage, um interne Werte zu konstruieren — URLs in Mails, Cache-Keys, Redirects, Login-Cookies. Wenn der Host-Header durch User-Input gesetzt werden kann, lassen sich diese Werte manipulieren.
Klassisches Beispiel: Password-Reset-Hijacking.
# Schadhaft: Reset-Link aus Host-Header gebaut
@app.post('/password-reset')
def password_reset():
email = request.form['email']
token = generate_token(email)
host = request.headers['Host'] # vom Angreifer kontrolliert!
reset_url = f"https://{host}/reset?token={token}"
send_email(email, f"Reset link: {reset_url}")
return 'OK'Angreifer schickt:
POST /password-reset HTTP/1.1
Host: attacker.example
Content-Type: application/x-www-form-urlencoded
email=victim@example.comWenn der Server keinen Front-End-Host-Filter hat, baut er den Reset-Link mit Angreifer-Domain. Das Opfer bekommt eine Mail vom echten Service mit echtem Token — aber Link auf Angreifer-Server. Klick → Angreifer hat den Token → kann Passwort zurücksetzen.
Weitere Host-Header-Injection-Angriffe
Cache-Poisoning über Host-Header:
GET /index.html HTTP/1.1
Host: attacker.example
X-Forwarded-Host: attacker.exampleWenn die Anwendung Inhalte vom Host-Header in die Antwort einbaut (z. B. absolute URLs zu CSS/JS), und die Antwort im Cache landet, sehen alle nachfolgenden Besucher:innen die manipulierten URLs — und laden CSS/JS vom Angreifer.
Routing-Bypass: Manche Multi-Tenant-Setups routen basierend auf Host-Header. Manipulation kann zu unbeabsichtigten Tenant-Switches führen.
Login-Cookie-Domain-Manipulation:
Wenn das Cookie auf Set-Cookie: ... Domain={host} gesetzt wird, kann Angreifer Cookie auf falsche Domain platzieren.
SSRF über Host-Header: Wenn die Anwendung im Backend basierend auf Host-Header weitere HTTP-Anfragen macht (z. B. interne Service-Discovery), führt Host-Header-Manipulation zu SSRF.
Host-Header-Injection verhindern
Drei Schichten:
1. Strenge Host-Whitelist. Anwendung akzeptiert nur explizit erlaubte Host-Header. Anfragen mit fremdem Host-Header werden mit 400 abgelehnt.
// Express-Middleware
const ALLOWED_HOSTS = new Set(['example.com', 'www.example.com', 'api.example.com']);
app.use((req, res, next) => {
if (!ALLOWED_HOSTS.has(req.hostname)) {
return res.status(400).send('Invalid host');
}
next();
});2. Reverse-Proxy enforce-Default. Nginx, Caddy oder Traefik so konfigurieren, dass nur erlaubte Host-Header durchgelassen werden:
server {
listen 443 ssl;
server_name example.com www.example.com;
# Kein default_server — andere Hosts laufen ins Leere
...
}
server {
listen 443 ssl default_server;
server_name _;
return 400; # alle anderen Host-Header ablehnen
}3. URL-Konstruktion aus Konfiguration, nicht aus Request.
Anwendung baut keine URLs aus Host:-Header. Stattdessen aus einer hartkodierten Server-Konfiguration:
# Sicher
BASE_URL = os.environ['APP_BASE_URL'] # z.B. "https://example.com"
@app.post('/password-reset')
def password_reset():
email = request.form['email']
token = generate_token(email)
reset_url = f"{BASE_URL}/reset?token={token}" # Host aus Config
send_email(email, f"Reset link: {reset_url}")
return 'OK'Vergiss auch nicht X-Forwarded-Host, X-Forwarded-Server, X-Forwarded-Proto und ähnliche Header — sie werden von Reverse-Proxies oft an Backend weitergereicht und sind ebenso manipulierbar, wenn das Front-End sie nicht überschreibt.
Gemeinsame Lehre: HTTP-Schicht-Hygiene
Beide Angriffsklassen — Request Smuggling und Host-Header-Injection — zeigen, dass die HTTP-Protokoll-Schicht selbst eine Sicherheits-Sphäre ist. App-Code-Härtung allein reicht nicht; Reverse-Proxy-Konfiguration, Backend-HTTP-Parsing-Verhalten und Header-Hygiene sind eigenständige Themen.
Was beide Klassen verbindet:
- Diskrepanzen zwischen Schichten sind die Angriffs-Wurzel (Front-End vs. Backend bei Smuggling; Reverse-Proxy vs. App bei Host-Header).
- Standards sind streng, Implementierungen sind tolerant. Browsers, Proxies, Backends akzeptieren oft mehr als der Standard erlaubt — genau dort entstehen Lücken.
- Test-Automatisierung ist schwach. Diese Angriffe brauchen manuelles Verständnis der HTTP-Schicht; Standard-Scanner finden sie nicht zuverlässig.
Für Web-Sicherheits-Reife heißt das: HTTP-Schicht ist nicht nur „Infrastruktur" — sie ist Teil der Anwendungs-Sicherheit. Reverse-Proxy-Konfiguration verdient denselben Code-Review wie App-Code.
Besonderheiten
James Kettle als Forschungs-Pionier
Die meisten heute bekannten Request-Smuggling-Varianten gehen auf James Kettle bei PortSwigger zurück. Sein DEF-CON-Vortrag "HTTP Desync Attacks: Request Smuggling Reborn" (2019) hat das Thema modernisiert. Spätere Forschung 2021 zu HTTP/2-Downgrade-Smuggling und 2023 zur Single-Packet-Attack ergänzt das Bild.
HTTP/2 löst nicht alles
HTTP/2 hat die klassischen CL/TE-Klassen strukturell eliminiert — aber HTTP/2-Frame-Parsing hat eigene Schwachstellen, und der häufige Fall „HTTP/2 vorn, HTTP/1.1 hinten" bringt das Problem zurück. End-to-End-HTTP/2 ist die saubere Lösung, aber operationell oft nicht durchgesetzt.
Bug-Bounty-Welt liebt Request Smuggling
Smuggling-Bugs zahlen typisch im hohen vierstelligen bis fünfstelligen Dollar-Bereich. Reports gegen Slack, GitHub, AWS, Microsoft, Google waren in den letzten Jahren öffentlich dokumentiert. Wer Bug-Bounty-Berichte verfolgt, sollte HackerOne und PortSwigger-Blog regelmäßig lesen.
Cloudflare und WAF helfen — und schaffen Probleme
WAFs (Cloudflare, AWS WAF, Akamai) können Standard-Smuggling-Patterns blockieren. Gleichzeitig sind sie selbst ein neuer Layer mit eigener HTTP-Interpretation — neue Diskrepanzen sind möglich. Wer WAF einsetzt: das ist ein Sicherheits-Gewinn, ersetzt aber nicht Backend-Härtung.
Host-Header-Injection ist subtil
Anders als XSS oder SQLi sieht der Angriff harmlos aus — der/die Angreifer:in sendet einfach eine Anfrage mit fremdem Host:-Header. Erst die Folgen in der Anwendung (Mail-Link, Cache-Eintrag, Redirect) machen es zum Angriff. Viele Apps haben das Problem über Jahre, ohne dass es bemerkt wird.
Frameworks helfen — wenn sie richtig konfiguriert sind
Django hat ALLOWED_HOSTS als Pflicht-Setting in Production. Rails hat ähnliche Mechanismen. Wer in einem dieser Frameworks arbeitet: Setting prüfen, nicht auf Default verlassen. Express, Flask, FastAPI haben kein eingebautes Pendant — eigene Middleware nötig.
HTTP Smuggler von Albinowax
Das Burp-Plugin HTTP Request Smuggler ist die De-facto-Standard-Test-Lösung. Automatisiert die wichtigsten Smuggling-Varianten und zeigt verschiedene Eskalationen. Wer Pentests betreibt: Pflicht-Toolkit.
Weiterführende Ressourcen
Externe Quellen
- PortSwigger Web Security Academy – Request Smuggling
- James Kettle – HTTP Desync Attacks (DEF CON 2019)
- James Kettle – HTTP/2 Smuggling Research (2021)
- HTTP Request Smuggler – Burp-Plugin
- OWASP HTTP Request Smuggling Defense Cheat Sheet
- Acunetix – Host Header Attack Detection
- Django ALLOWED_HOSTS
- RFC 7230 – HTTP/1.1 Message Syntax
- RFC 9112 – HTTP/1.1 (Update 2022)