Zum Inhalt springen

Host Header Injection

CWE-644CWE-601OWASP A03:2021Aktualisiert 4. September 20265 Min. Lesezeit

Viele Anwendungen leiten ihre eigene Adresse aus dem Host-Header der eingehenden Anfrage ab. Dieser Header wird vom Client gesetzt, ein Angreifer kann ihn also ersetzen. Landet dieser Wert in einem Link zur Passwortwiederherstellung, wird das Wiederherstellungstoken an den Server des Angreifers gesendet, sobald das Opfer darauf klickt.

Eine Anwendung muss mitunter ihre eigene Adresse kennen: um einen Link in eine E-Mail zu setzen, um einen absoluten Verweis aufzubauen, um zu bestimmen, welcher Kunde bedient wird. Die einfachste Quelle dafür scheint der Host-Header der eingehenden Anfrage zu sein. Nur gehört diese Quelle nicht Ihnen, sondern demjenigen, der die Anfrage sendet. Wohin das führt, ist selten harmlos.

Was ist Host Header Injection?

Jede HTTP-Anfrage enthält einen Host-Header mit dem Namen des angesprochenen Servers. Dieser Header ist nötig, weil eine IP-Adresse viele Domains bedienen kann; er teilt dem Webserver mit, welche Website gemeint ist. Von Host Header Injection sprechen wir, wenn eine Anwendung diesen Wert in ihre eigene Ausgabe übernimmt, ohne zu prüfen, ob es sich um eine ihrer eigenen Adressen handelt.

Der Denkfehler ist fein, aber grundlegend. Der Host-Header wirkt wie Infrastruktur, wie etwas, das zum Server gehört und nicht zum Nutzer. In Wirklichkeit steht er schlicht in der Anfrage, und jeder, der Anfragen selbst zusammenstellt, kann darin eintragen, was er möchte. Es handelt sich also um eine Eingabe, und sie verdient dasselbe Misstrauen wie ein Formularfeld.

Stellen Sie sich einen Rückumschlag vor, auf dem der Absender die Rücksendeadresse selbst einträgt. Das Formular kommt ordnungsgemäß bei Ihnen an, und Sie senden die Antwort an die angegebene Adresse zurück. Dass die Antwort damit anderswo landet als beim rechtmäßigen Empfänger, fällt erst auf, wenn es zu spät ist.

Wie läuft ein Host-Header-Injection-Angriff ab?

Der greifbarste Missbrauch steckt in der Funktion zur Passwortwiederherstellung, denn dort wird ein Geheimnis per E-Mail versandt.

Verwundbar:

app.post('/passwort-vergessen', async (req, res) => {
  const nutzer = await nutzerRepo.findeUeberEmail(req.body.email);
  if (nutzer) {
    const token = await erstelleWiederherstellungstoken(nutzer);

    // Basis-URL aus der Anfrage: vom Angreifer bestimmbar
    const link = `https://${req.headers.host}/wiederherstellen?token=${token}`;
    await mail.sende(nutzer.email, `Stellen Sie Ihr Passwort wieder her: ${link}`);
  }
  res.send('Sofern uns diese Adresse bekannt ist, erhalten Sie eine E-Mail.');
});

Der Angreifer beantragt eine Wiederherstellung für die Adresse des Opfers, passt jedoch den Header an:

POST /passwort-vergessen HTTP/1.1
Host: boesartig.example
Content-Type: application/json

{"email":"j.walter@firma.de"}

Das Opfer erhält eine E-Mail, die tatsächlich von Ihrer Organisation stammt, mit der richtigen Anrede und dem richtigen Betreff. Nur verweist der Link auf https://boesartig.example/wiederherstellen?token=.... Klickt es darauf, erhält der Server des Angreifers das gültige Wiederherstellungstoken, mit dem dieser anschließend selbst das Passwort setzen kann. Das Opfer hat nichts Verdächtiges gesehen: Es hatte schließlich selbst um eine Wiederherstellung gebeten, oder glaubte das zumindest.

Sicher:

// Die Anwendung weiß selbst, unter welcher Adresse sie läuft
const BASIS_URL = process.env.BASIS_URL;             // https://portal.example

app.post('/passwort-vergessen', async (req, res) => {
  const nutzer = await nutzerRepo.findeUeberEmail(req.body.email);
  if (nutzer) {
    const token = await erstelleWiederherstellungstoken(nutzer);
    const link = `${BASIS_URL}/wiederherstellen?token=${token}`;
    await mail.sende(nutzer.email, `Stellen Sie Ihr Passwort wieder her: ${link}`);
  }
  res.send('Sofern uns diese Adresse bekannt ist, erhalten Sie eine E-Mail.');
});

// Auffangnetz: Anfragen mit unbekanntem Hostnamen abweisen
const ERLAUBTE_HOSTS = new Set(['portal.example', 'www.portal.example']);

app.use((req, res, next) => {
  const host = req.headers.host?.split(':')[0];
  if (!ERLAUBTE_HOSTS.has(host)) return res.status(400).send('Ungültiger Host');
  next();
});

Die Basis-URL stammt nun aus der Konfiguration und ist damit eine Eigenschaft der Installation statt der Anfrage. Die ergänzende Prüfung sorgt dafür, dass Anfragen mit unbekanntem Hostnamen gar nicht erst verarbeitet werden, womit auch die Varianten abgefangen werden, die Sie noch nicht bedacht hatten. Bedienen Sie mehrere Domains, bestimmen Sie die Basis-URL anhand eines geprüften Werts aus dieser Liste.

Vergessen Sie X-Forwarded-Host nicht. Viele Frameworks nutzen diesen Header bei der Bestimmung der Basis-URL, wenn die Anwendung hinter einem Proxy läuft. Wird er von jedem Client akzeptiert statt nur von Ihrem eigenen vertrauenswürdigen Proxy, lässt sich der Schutz am Host-Header mühelos umgehen.

Welche Auswirkungen hat Host Header Injection?

Der Schweregrad reicht von mittel bis hoch, wobei der Weg über die Passwortwiederherstellung am schwersten wiegt. Dort führt die Schwachstelle zu einer vollständigen Kontoübernahme, ohne dass der Angreifer außer der E-Mail-Adresse etwas über das Opfer wissen müsste.

Wirksam macht den Angriff seine Glaubwürdigkeit. Die E-Mail kommt tatsächlich von Ihnen: Sie wird von Ihrem Server versandt, stammt von Ihrer Domain, besteht Ihre SPF- und DKIM-Prüfungen und sieht genau so aus, wie Ihre Nutzer es gewohnt sind. Es gibt kein Signal, das eine aufmerksame Empfängerin warnen würde, außer dem Link selbst, und der wird bei einer erwarteten E-Mail selten geprüft.

Über E-Mail hinaus gibt es weitere Folgen. Wird die Antwort zwischengespeichert, kann eine vergiftete Fassung mit Verweisen auf die Domain des Angreifers an andere Besucher ausgeliefert werden. In Umgebungen, in denen ein Proxy anhand des Hostnamens routet oder autorisiert, kann ein manipulierter Header Verkehr zu einer internen Anwendung lenken. Und bei Anwendungen, die anhand der Subdomain eine Kundenumgebung auswählen, kann er Zugriff auf fremde Daten verschaffen.

Wie spürt man Host Header Injection auf?

Ein Tester sendet Anfragen mit geändertem Host-Header und prüft, ob dieser Wert irgendwo in der Antwort wieder auftaucht: in einer Weiterleitung, in einem absoluten Link im HTML, in einem Location-Header oder in einem Verweis auf eine Skriptdatei. Erscheint der angegebene Wert, wird der Header irgendwo übernommen.

Der wichtigste Test betrifft die Funktion zur Passwortwiederherstellung, da die Wirkung dort am deutlichsten ist: eine Wiederherstellung mit abweichendem Host beantragen und prüfen, welcher Link in der E-Mail landet. Weiter wird versucht, ob sich die Prüfung mit X-Forwarded-Host, mit einer Portnummer hinter dem Hostnamen, mit einem doppelten Host-Header oder mit einer absoluten URL in der Anfragezeile umgehen lässt. Auch das Cache-Verhalten wird betrachtet: Wird eine Antwort mit fremdem Host gespeichert und an andere ausgeliefert? AssistSec bezieht die vollständige Kette einschließlich des vorgelagerten Proxys oder Lastverteilers ein, denn dort wird beantwortet, welche Komponente den Hostnamen bestimmen darf.

Wie verhindert man Host Header Injection?

  • Beziehen Sie die Basis-URL aus Ihrer Konfiguration und nie aus dem Host-Header der Anfrage.
  • Weisen Sie Anfragen ab, deren Hostname nicht auf Ihrer Liste erlaubter Domains steht.
  • Akzeptieren Sie X-Forwarded-Host und ähnliche Header ausschließlich von Ihrem eigenen vertrauenswürdigen Proxy.
  • Bauen Sie Links in E-Mails stets mit dem konfigurierten Wert auf, auch in Hintergrundprozessen.
  • Richten Sie Ihren Webserver mit einem ausdrücklichen Standardhost ein, der unbekannte Namen abweist.
  • Halten Sie den Hostnamen aus zwischengespeicherten Antworten heraus oder lassen Sie den Cache auf diesem Wert variieren.
  • Wählen Sie eine Kundenumgebung anhand eines geprüften Werts aus, nicht anhand des rohen Headers.
  • Prüfen Sie bei einer Passwortwiederherstellung, dass das Token nur auf Ihrer eigenen Domain verwendbar ist.

Quellen

Häufige Fragen

Warum lässt sich dem Host-Header nicht trauen?

Weil er Teil der Anfrage ist und damit vollständig vom Absender gesetzt wird. Ein Browser füllt ihn korrekt aus, doch ein Angreifer, der Anfragen selbst zusammenstellt, trägt darin ein, was er will. Alles, was der Server daraus ableitet, ist damit vom Angreifer beeinflussbar.

Was sind X-Forwarded-Host und ähnliche Header?

Header, die ein Proxy hinzufügt, um den ursprünglichen Hostnamen weiterzugeben. Viele Frameworks berücksichtigen sie bei der Bestimmung der Basis-URL. Kommen sie unmittelbar von einem Client, sind sie ebenso unzuverlässig wie der Host-Header, und sie werden häufiger übersehen.

Wie setze ich die Basis-URL dann richtig?

Als festen Wert in Ihrer Konfiguration, je Umgebung. Die Anwendung sollte wissen, unter welcher Adresse sie erreichbar ist; das ist eine Eigenschaft der Installation und nichts, was sich je Anfrage unterscheidet. Bei mehreren Domains führen Sie eine Liste und prüfen dagegen.

Ist das auch ohne E-Mail ein Risiko?

Ja. Der Header kann auch im Cache landen, wodurch eine vergiftete Seite mit Verweisen auf die Domain des Angreifers an andere Besucher ausgeliefert wird. Weiter lässt er sich nutzen, um Routing-Entscheidungen oder Zugriffskontrollen in einem Proxy zu beeinflussen.

Verwandte Artikel

Zum Suchen / drücken · Esc