Web Cache Poisoning - Cache-basierter Angriff
Web Cache Poisoning ist ein Angriff bei dem ein Angreifer unkeyed HTTP-Header oder Parameter nutzt um schädliche Inhalte in einen Web-Cache einzuschleusen. Diese gecachten Inhalte werden dann an andere Nutzer ausgeliefert ohne dass der Origin-Server kontaktiert wird. Angriffsvektoren: manipulierte HTTP-Header (X-Forwarded-Host, X-Forwarded-Scheme), fatcookies, Query-String-Parameter. Resultat: XSS, Open Redirect, Denial of Service gegen viele Nutzer gleichzeitig.
Web Cache Poisoning ist eine der heimtückischsten Schwachstellenklassen - ein Angreifer sendet einen einzigen Request, der im Cache landet, und danach erhalten potenziell tausende Nutzer schädliche Inhalte. Kein direkter Zugriff auf andere Nutzer nötig: der Cache übernimmt die Auslieferung.
Cache-Mechanismus und Keyed vs. Unkeyed
Normaler Request-Flow:
Client → CDN/Reverse-Proxy → (Cache-Miss) → Origin-Server → Client ← CDN (Response gecacht)
Nächster Request: Client → CDN → (Cache-Hit!) → gecachte Response (kein Server-Kontakt!)
Cache-Key (was den Cache-Eintrag identifiziert):
- Standard: URL + HTTP-Methode
- Optional: Accept-Encoding, Accept-Language, Cookies
Unkeyed Inputs (vom Cache ignoriert, aber vom Origin verarbeitet!):
X-Forwarded-Host: evil.comX-Forwarded-Scheme: httpX-Forwarded-Port: 8080X-Host: attacker.comX-Original-URL: /adminX-Forwarded-For: 127.0.0.1- Bestimmte HTTP-Header (Via, X-Rewrite-URL)
- Unbekannte Query-Parameter:
?utm_content=<xss>
Angriffsprinzip:
- Angreifer sendet Request mit bösem unkeyed Header
- Origin-Server verarbeitet diesen Header (z.B. baut URL daraus)
- Response enthält Angreifer-Content, wird OHNE den Header gecacht
- Andere Nutzer bekommen dieselbe gecachte Antwort
Kritisch: Origin reflektiert unkeyed Inputs in Responses! Beispiel:
X-Forwarded-Host→ wird in<script src="...">eingebettet.
Angriffstypen
1. Web Cache Poisoning → XSS
GET /page HTTP/1.1
Host: victim.com
X-Forwarded-Host: evil.com
Origin-Response (gecacht!):
<script src="https://evil.com/static/analytics.js"></script>
Alle folgenden User erhalten XSS-Payload via Cache!
Variante - Query-Parameter Reflection:
GET /search?term=<script>alert(1)</script>&utm_content=CACHE HTTP/1.1
→ Wenn `utm_content` unkeyed: Response wird gecacht MIT XSS in term-Reflection!
2. Cache Poisoning → Open Redirect
GET / HTTP/1.1
Host: victim.com
X-Forwarded-Scheme: http (Origin baut Redirect: http://victim.com/ → 301)
→ Gecachter 301-Redirect auf http (statt https) → Downgrade-Angriff + mögliche MITM-Kette
3. Fat GET Body / Parameter Cloaking
GET /api/data?legit=param HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 21
param=value&evil=injected
- Manche Server lesen GET-Body als Parameter (non-standard!)
- Cache keyt nur URL-Query-String, nicht Body
- GET-Body-Parameter sind “unkeyed”!
4. Cache Key Normalization Bypass
GET /admin HTTP/1.1 ← Admin-Seite (nicht gecacht wegen Auth)
GET /ADMIN HTTP/1.1 ← Gleiche Response? Cache normalisiert auf /admin?
Anwendung:
- Cache normalisiert Port-Nummer weg:
:443ignoriert - Cache normalisiert URL-Encoding:
%2F=/ - Angreifer sendet
/admin%2F?poison=1→ gecachter Redirect auf/admin/
5. Cache Poisoning → Denial of Service
GET /critical-resource HTTP/1.1
X-Forwarded-Scheme: https (wenn nur HTTP erlaubt: 400 Error!)
- Origin antwortet mit 400 Bad Request
- Cache cached den 400-Error für
/critical-resource - Alle Users erhalten 400 für alle Requests!
- Komplette Service-Disruption!
Erkennung im Pentest
1. Burp Extension: param-miner
- Findet automatisch unkeyed Header und Parameter!
- Installation: Burp App Store → param-miner
- Einfacher Start: Rechtsklick → Guess headers/params
2. Manuelles Testing - unkeyed Header identifizieren
a) Cache-Verhalten verstehen:
- Mehrfacher Request: erstes Mal Cache-Miss (
X-Cache: MISS) - Zweites Mal: Cache-Hit (
X-Cache: HIT) - Sicherstellen: uniquen Cache-Buster in URL nutzen:
GET /page?cachebuster=abc123
b) Unkeyed Header testen:
GET /page?cb=001 HTTP/1.1
X-Forwarded-Host: test.com
→ Response: enthält "test.com"? (Reflection!)
→ Nächster Request (ohne Header, gleiche URL):
GET /page?cb=001 HTTP/1.1
→ Immer noch "test.com" in Response? → Header ist UNKEYED!
3. Gefährliche Reflection-Punkte finden
Suchen nach unkeyed Header-Inhalten in Response:
<script src="...">Tags<link href="...">Tags- JavaScript-Variablen:
var BASE_URL = "..." - Meta-Refresh:
<meta http-equiv="refresh" content="0; url=..."> - Location-Header (bei Redirects)
- CORS Header (Access-Control-Allow-Origin)
4. Cache-Timing-Analyse
- Response-Zeit beim Cache-Miss > Cache-Hit?
- Age-Header: wie lange gecacht?
- Cache-Control: max-age=…
- Vary-Header: welche Header beeinflussen Cache-Key?
Wichtige Response-Header für Analyse:
| Header | Bedeutung |
|---|---|
X-Cache: HIT / MISS | Cache-Status |
Age: <Sekunden> | Zeit seit Caching |
CF-Cache-Status: HIT / MISS / EXPIRED | Cloudflare-Status |
X-Varnish: <ID> | Varnish Cache |
Cache-Control: public, max-age=3600 | Cache-Direktiven |
Vary: Accept-Encoding, Accept-Language | Cache-Key-Varianten |
Schutzmaßnahmen
1. Unkeyed Header aus Responses entfernen
X-Forwarded-HostNIEMALS in URLs oder Scripts reflektieren!- Input-Validation: Hostnamen auf Allowlist prüfen
# Nginx - sichere Host-Normalisierung:
set $safe_host $host; # Nur Host-Header, ignoriert X-Forwarded-*
add_header Content-Security-Policy "default-src 'self'";
# Apache - X-Forwarded-Host blocken:
RequestHeader unset X-Forwarded-Host
2. Cache-Key erweitern (alle relevanten Header einbeziehen)
# Varnish VCL:
sub vcl_hash {
hash_data(req.url);
hash_data(req.http.host);
hash_data(req.http.X-Forwarded-Proto); // HTTPS vs HTTP
return (lookup);
}
# Nginx Proxy Cache:
proxy_cache_key "$scheme$request_method$host$request_uri$http_accept_language";
3. Security Headers auf gecachten Responses
# CSP verhindert Auswirkung von Cache-Poisoning → XSS
Content-Security-Policy: default-src 'self'; script-src 'self'
# Verhindert Downgrade via Redirect-Poisoning:
Strict-Transport-Security: max-age=31536000; includeSubDomains
4. Cache nur für sichere Inhalte aktivieren
- Dynamische Seiten mit User-spezifischen Inhalten: NICHT cachen!
- Nur statische Assets (JS, CSS, Bilder) aggressiv cachen
- HTML-Seiten: kurze TTL (max. 1 Minute) oder revalidate
5. Vary-Header korrekt setzen
# Wenn Response von Accept-Language abhängt: in Cache-Key!
Vary: Accept-Language, Accept-Encoding
6. Anomalie-Erkennung
- Alerts bei unerwarteten
X-Forwarded-*Header-Werten - WAF-Regel:
X-Forwarded-Host≠ eigener Hostname → blockieren - Monitoring: plötzliche Cache-Hit-Rate-Änderungen → mögliche Poisoning-Attacke
Zusammenfassung sichere Architektur
- Keinen User-Input in gecachten Responses reflektieren
- Trusted-Proxy-Header nur von bekannten IPs akzeptieren
- Cache-Key alle request-varianten Inputs einschließen
- CSP als Last Line of Defense gegen XSS-Auswirkung