Zum Inhalt springen

CRLF Injection und HTTP Response Splitting

CWE-113OWASP A03:2021Aktualisiert 31. August 20266 Min. Lesezeit

CRLF Injection ist eine Schwachstelle, bei der ein Angreifer einen Zeilenumbruch in einen HTTP-Header einschleust und so eigene Header ergänzt oder die Antwort in zwei Nachrichten spaltet. CRLF steht für Carriage Return und Line Feed, die Steuerzeichen, die jede Headerzeile beenden. Die Lösung: Steuerzeichen ablehnen und Header nur über die Framework-API setzen.

Eine HTTP-Antwort ist reiner Text mit einem strengen Aufbau: Jede Headerzeile endet mit einem Zeilenumbruch, und eine Leerzeile trennt die Header vom Body. Sobald ungefilterte Benutzereingaben in einen Header-Wert gelangen, liefert ein Angreifer diesen Zeilenumbruch selbst mit und übernimmt damit die Struktur der Nachricht. Das nennt man CRLF Injection. Im Folgenden lesen Sie, wie das funktioniert und was Sie dagegen tun.

Was ist CRLF Injection?

CRLF Injection ist eine Schwachstelle, bei der ein Angreifer einen Zeilenumbruch in einen HTTP-Header-Wert einschleust und dadurch eigene Header ergänzt oder die Antwort in zwei getrennte Nachrichten spaltet. CRLF steht für Carriage Return und Line Feed: die beiden Steuerzeichen, geschrieben als \r und \n, mit denen HTTP/1.1 jede Headerzeile abschließt. Zwei dieser Paare hintereinander, also eine Leerzeile, markieren das Ende der Header und den Beginn des Bodys.

Ein Vergleich aus dem Alltag: Sie diktieren einer Schreibkraft eine Adresse, die genau das notiert, was sie hört. Sagt jemand mitten im Diktat laut “neue Zeile, Absender ist Jansen”, tippt die Schreibkraft das brav als neues Feld. Sie kann nicht heraushören, welcher Teil des Gesagten Ihre Daten waren und welcher Teil eine Anweisung zum Aufbau. Ein HTTP-Parser verhält sich mit den Zeichen 13 und 10 genauso.

Die Folgen werden in zwei Abstufungen beschrieben. Bei Header Injection ergänzt der Angreifer eine oder mehrere zusätzliche Headerzeilen in einer ansonsten normalen Antwort, etwa ein selbst gewähltes Set-Cookie. Bei HTTP Response Splitting sendet er zusätzlich die Leerzeile und schreibt eine vollständige zweite Antwort mit eigener Statuszeile, eigenen Headern und eigenem Body.

Wie funktioniert ein CRLF-Injection-Angriff?

Nehmen wir einen Endpunkt, der den Benutzer nach der Anmeldung auf die Seite zurückschickt, von der er kam. Das Ziel stammt aus einem Query-Parameter und geht unverändert in den Location-Header. Im Beispiel setzt der Code die Antwort selbst als Text zusammen, so wie es in einer eigenen HTTP-Schicht, in einem Proxy oder in älterem Code geschieht, der direkt in den Socket schreibt.

Verwundbar:

function sendRedirect(socket, next) {
  // Die Antwort wird als reiner Text gebaut und ungeprüft geschrieben
  const response =
    "HTTP/1.1 302 Found\r\n" +
    "Location: " + next + "\r\n" +
    "Content-Length: 0\r\n" +
    "\r\n";

  socket.write(response);
}

Ein normaler Benutzer ruft /go?next=/dashboard auf und wird wie erwartet weitergeleitet. Ein Angreifer setzt in denselben Parameter einen URL-kodierten Zeilenumbruch, %0d%0a, gefolgt von einem Header seiner Wahl:

GET /go?next=/dashboard%0d%0aSet-Cookie:%20session=6f21ab%3B%20Path=/ HTTP/1.1
Host: app.example.com

Der Server dekodiert den Parameter und fügt den Wert in den Header ein. Tatsächlich über die Leitung geht dies:

HTTP/1.1 302 Found
Location: /dashboard
Set-Cookie: session=6f21ab; Path=/
Content-Length: 0

Für den Browser ist die dritte Zeile nicht von einem Header zu unterscheiden, den Ihre Anwendung selbst gesetzt hat. Damit bestimmt der Angreifer das Session-Cookie des Opfers: Er lockt jemanden auf den Link, der Server setzt die Session-Kennung, die der Angreifer bereits kennt, und sobald sich das Opfer anmeldet, teilt er diese Sitzung. Das ist Session Fixation, ausgelöst durch einen Header, den Sie nie geschrieben haben.

Sendet er zwei Zeilenumbrüche hintereinander, endet die erste Antwort und es beginnt eine neue, die er selbst füllt, samt eigenem Content-Type und einem Body mit HTML oder Skript.

Die Lösung hat zwei Ebenen: Ein Header darf niemals frei vom Benutzer gewählten Text enthalten, und Sie setzen ihn über die Header-API Ihres Frameworks statt über selbst zusammengebauten Antworttext.

Sicher:

const ERLAUBTE_PFADE = new Set(["/dashboard", "/profil", "/einstellungen"]);

function sendRedirect(res, next) {
  // 1. Jedes Steuerzeichen ablehnen, nicht nur CR und LF
  if (typeof next !== "string" || /[\x00-\x1f\x7f]/.test(next)) {
    res.writeHead(400).end("Ungültiger Parameter");
    return;
  }

  // 2. Allowlist: Der Header erhält nur einen Wert, den der Server selbst kennt
  const target = ERLAUBTE_PFADE.has(next) ? next : "/dashboard";

  // 3. Framework-API statt selbst gebautem Antworttext
  res.writeHead(302, { Location: target });
  res.end();
}

Node.js weist einen Header-Wert mit Zeilenumbruch ab und wirft einen Fehler, und die meisten modernen Frameworks verhalten sich ähnlich. Betrachten Sie diese Prüfung als Auffangnetz, nicht als Ihren Entwurf. Die Allowlist sorgt dafür, dass gar nichts vom Benutzer Erdachtes in den Header gelangt, und sie trägt auch dann noch, wenn irgendwann eine weniger strenge Komponente davorgeschaltet wird.

Filtern Sie niemals nur auf das vollständige Paar aus Carriage Return und Line Feed. Viele Parser akzeptieren auch ein einzelnes Line Feed als Zeilenende, und manche Stacks wandeln bei einer Zeichensatzkonvertierung bestimmte Unicode-Zeichen doch noch in eines dieser Steuerzeichen um. Lehnen Sie deshalb den gesamten Bereich der Steuerzeichen ab, statt zwei Zeichen auf eine Sperrliste zu setzen.

Welche Auswirkungen hat CRLF Injection?

Der Schweregrad hängt davon ab, was der Angreifer in die Antwort schreiben kann und wer diese Antwort erhält. Manipuliert er nur seine eigene Antwort, ist das berichtenswert, aber ohne Opfer. Kann er einen Header erzwingen, der den Browser einer anderen Person steuert, wird es ernst: Ein gefälschtes Set-Cookie führt zu Session Fixation und damit zum Zugriff auf das Konto des Opfers, und eine vollständige zweite Antwort mit HTML ergibt Cross-Site Scripting im Kontext Ihrer eigenen Domain.

Die schwerste Variante läuft über Caching. Speichert ein Reverse Proxy, ein CDN oder der Browser-Cache die gespaltene Antwort unter der URL einer normalen Seite, liefert dieses System anschließend jedem Besucher den Inhalt des Angreifers aus, auch denen, die den bösartigen Link nie angeklickt haben. Aus einem Fehler in einem einzigen Parameter wird so eine Verunstaltung oder eine Phishing-Seite auf Ihrer eigenen Domain, die bestehen bleibt, bis der Cache geleert wird.

Geschäftlich bedeutet das übernommene Konten, Ansehensverlust und, sobald personenbezogene Daten betroffen sind, eine Meldepflicht. Weil die Reichweite je nach Situation stark schwankt, reicht die Einstufung von mittel bis hoch.

Wie erkennen Sie CRLF Injection?

Beginnen Sie mit einer Bestandsaufnahme aller Stellen, an denen Eingaben in einen Header gelangen: das Location einer Weiterleitung, ein Set-Cookie mit einer Spracheinstellung oder einem Rücksprungpfad, der Dateiname im Content-Disposition eines Downloads sowie eigene Header, die eine Anfrage-Kennung oder einen Mandantennamen zurückgeben.

Getestet wird, indem Sie in einen solchen Parameter einen kodierten Zeilenumbruch und dahinter einen harmlosen eigenen Header mit einem gut erkennbaren Wert setzen. Betrachten Sie anschließend die rohe Antwort, etwa mit einem Intercepting Proxy wie Burp oder mit curl und der Option zur Anzeige der Header, und nicht die Darstellung im Browser, die Header gar nicht zeigt. Erscheint Ihr Testheader als eigene Zeile, liegt ein Befund vor. Bleibt alles unverändert, versuchen Sie ein einzelnes Line Feed und eine doppelt kodierte Variante.

Prüfen Sie außerdem die gesamte Kette und nicht nur die Anwendung: Der Anwendungsserver kann den Wert ablehnen, während der Proxy davor ihn dennoch durchreicht. Scanner melden den Lehrbuchfall zuverlässig, übersehen aber, was hinter der Authentifizierung liegt oder erst im Zusammenspiel zweier Server entsteht. AssistSec prüft diesen Bereich im Rahmen eines Penetrationstests und zeigt je Befund die rohe Antwort, in der die zusätzliche Headerzeile auftaucht.

Wie verhindern Sie CRLF Injection?

  • Setzen Sie Header über die API Ihres Frameworks. Bauen Sie Antworttext niemals selbst zusammen. Die eingebauten Funktionen prüfen den Wert und weisen Steuerzeichen ab.
  • Lehnen Sie Steuerzeichen bereits bei der Eingabe ab. Verwerfen Sie den gesamten Bereich der Steuerzeichen, nicht nur Carriage Return und Line Feed, und zwar nach dem Dekodieren des Parameters.
  • Arbeiten Sie mit einer Allowlist für Header-Werte. Lassen Sie den Benutzer aus einer festen Menge von Pfaden, Sprachen oder Dateinamen wählen und übersetzen Sie diese Wahl serverseitig in den echten Wert.
  • Kodieren Sie Werte, die wirklich dynamisch sein müssen. Ein Dateiname im Content-Disposition gehört prozentkodiert dorthin, ein Wert in einem Cookie ebenso.
  • Prüfen Sie die gesamte Kette und halten Sie sie aktuell. Reverse Proxys, CDN-Regeln und eigene Middleware setzen ebenfalls Header, und veraltete Komponenten haben hier eine lange Fehlergeschichte.
  • Bereinigen Sie auch Ihre Logzeilen. Dieselben Zeichen fälschen Protokolleinträge und machen die Aufarbeitung eines Vorfalls unzuverlässig.

Quellen

Häufige Fragen

Wofür steht CRLF?

CRLF ist die Abkürzung für Carriage Return und Line Feed, die beiden Steuerzeichen mit den Codes 13 und 10, die zusammen einen Zeilenumbruch bilden. In HTTP/1.1 beendet dieses Paar jede Headerzeile, und eine Leerzeile, also zwei Paare hintereinander, trennt die Header vom Body. Wer diese Zeichen in einen Header-Wert bekommt, bestimmt damit den Aufbau der Nachricht und nicht nur ihren Inhalt.

Was ist der Unterschied zwischen CRLF Injection und HTTP Response Splitting?

CRLF Injection beschreibt die Technik: Ein Zeilenumbruch landet in einem Header-Wert. HTTP Response Splitting beschreibt die schwerste Folge davon: Der Angreifer sendet zusätzlich die Leerzeile und schreibt eine vollständige zweite Antwort mit eigener Statuszeile, eigenen Headern und eigenem Body. Die Zwischenstufe, bei der nur eine zusätzliche Headerzeile entsteht, heißt Header Injection.

Ist CRLF Injection noch relevant, wenn Frameworks Header prüfen?

Ja. Moderne Frameworks weisen einen Zeilenumbruch im Header-Wert ab, doch diese Prüfung schützt nur Code, der die Framework-API auch tatsächlich verwendet. Eigene HTTP-Schichten, Reverse Proxys, CDN-Regeln und ältere Komponenten setzen Header weiterhin als Zeichenkette zusammen. Hinzu kommt, dass nicht jede Station in der Kette dieselbe Prüfung durchführt.

Wie schwerwiegend ist CRLF Injection?

Das hängt davon ab, wer die manipulierte Antwort erhält. Kann der Angreifer nur seine eigene Antwort verändern, bleibt die Auswirkung begrenzt. Kann er einem anderen Benutzer ein Set-Cookie aufzwingen oder landet seine gespaltene Antwort in einem gemeinsamen Cache, führt das zu Session Fixation, Cross-Site Scripting oder Cache Poisoning, und die Einstufung steigt auf hoch.

Wie teste ich einen Parameter auf CRLF Injection?

Senden Sie in jedem Parameter, der in einem Antwort-Header landet, einen URL-kodierten Zeilenumbruch gefolgt von einem eigenen Header mit einem gut erkennbaren Wert. Betrachten Sie danach die rohe Antwort und nicht die Darstellung im Browser. Erscheint Ihr Testheader als eigene Zeile, ist der Parameter verwundbar; bleibt die Antwort unverändert, versuchen Sie ein einzelnes Line Feed und eine doppelt kodierte Variante.

Verwandte Artikel

Zum Suchen / drücken · Esc