HTTP Response Splitting (dt.: Aufteilung der HTTP-Antwort) ist eine Sicherheitslücke, die zur Durchführung von Cross-Site-Scripting-Attacken, (Cross-User-)Defacements, Web cache poisoning und ähnlichen Exploits verwendet werden kann.
Funktionsweise
Um die Attacke durchzuführen, werden mehrere Zeilenvorschübe gefolgt von den Daten des Angreifers per Header-Injection in den Header einer HTTP-Antwort eingefügt. Im HTTP-Standard signalisiert die erste Leerzeile das Ende des Header-Bereichs und damit in der Regel den Beginn der Nutzdaten. Wenn die Webanwendung es versäumt, Benutzereingaben zu prüfen und damit Zeilenvorschübe in einem Header erlaubt, dann kann ein möglicher Angreifer die Kontrolle über die Nutzlast übernehmen und die HTTP-Antwort in zwei Teile zerteilen. Wird für weitere Anfragen die gleiche TCP-Verbindung genutzt (HTTP-Pipelining), dann erscheint der zweite Teil der geteilten Antwort als Antwort auf die nächste Anfrage.
Gemäß dem Standard ist nur die Kombination „CR LF“ (carriage return + linefeed, in vielen Programmiersprachen als „\r\n“
darstellbar) das gültige Ende einer Header-Zeile. Allerdings akzeptieren viele User Agents auch ein einzelnes Auftreten von CR oder LF als Zeilenende.
Beim Benutzer besteht die zweite Antwort also aus den vom Angreifer injizierten Daten. Setzt dieser nun gezielt HTML oder JavaScript ein, so kommt es zur schlichten Verunstaltung (Defacement) oder sogar schwerwiegenden Cross-Site-Scripting-Angriffen.
Beim „Web Cache Poisoning“ (dt.: Cache-Vergiftung) wird der Header so modifiziert, dass Cache-relevante Header-Felder verändert werden, um die veränderte Seite in den Cache eines Webproxy einfließen zu lassen.
Beispiel
Angenommen sei eine Seite, deren Code ungeprüft eine GET-Variable in die Header übernimmt. Hier in PHP:
header("Location: ".$_GET["seite"]."\r\n");
Eine gutartige Anfrage könnte den Parameter seite
z. B. auf http://de.wikipedia.org setzen. Die HTTP-Antwort könnte dann so aussehen:
HTTP/1.1 301 Moved Permanently
Location: http://de.wikipedia.org/
Eine bösartige Seite allerdings könnte einen kompliziert aussehenden String wie den folgenden senden: %0d%0a%0a%3Chtml%3E%3Cbody%3Eerste Antwort%3C/body%3E%3C/html%3E%0d%0a%0d%0aHTTP/1.1 200 OK%0d%0aContent-Type: text/html%0d%0a%0d%0a%3Chtml%3E%3Cbody%3Ezweite Antwort%3C/body%3E%3C/html%3E
„Übersetzt“ man die URL-Kodierungen und injiziert diese wie oben in die Antwort, so erhält man
HTTP/1.1 301 Moved Permanently
Location:
<html><body>erste Antwort</body></html>
HTTP/1.1 200 OK
Content-Type: text/html
<html><body>zweite Antwort</body></html>
Es wurde also die eigentliche Antwort um eine zweite ergänzt. Diese Antwort würde jetzt bei der nächsten Anfrage über die gleiche HTTP-Verbindung an den Browser oder Proxy gesendet werden, obwohl dieser eigentlich eine andere Anfrage gestellt hat.
Abhilfe
Abhilfe schafft das gründliche Überprüfen aller Eingabeparameter, bevor diese in einen Header geschrieben werden. Dies kann auch von einer Bibliotheksfunktion übernommen werden.