Content Security Policy - Wie schwer kann es sein?

Content Security Policy

Wie schwer kann es sein?

Michael Schneider
von Michael Schneider
am 18. August 2016
Lesezeit: 12 Minuten

Keypoints

  • Die Content Security Policy (CSP) ist ein wichtiges Mittel zum Schutz von Webapplikationen
  • Ein korrektes Umsetzen ist sehr anspruchsvoll
  • Viele Entwickler und Administratoren sehen deshalb leider davon ab
  • Eine durchdachte Implementierung ist dennoch möglich und vorzuziehen

Die Content Security Policy (CSP) ist seit September 2015 ein eigener Prüfpunkt unserer Checkliste für einen Web Application Penetration Test. Eines der ersten Projekte danach ist sinnbildlich für die Akzeptanz und Umsetzung von CSP im Allgemeinen. In jenem Projekt wurden mehrere Cross Site Scripting-Schwachstellen (XSS) gefunden. Neben einer strikten Eingabevalidierung haben wir als zusätzliche Massnahme die Einführung eines CSP-Headers empfohlen. Die Entwickler haben dies auch umgesetzt und eine Policy definiert. Aber in der Direktive script-src wurde die Ausführung von Inline-JavaScript weiterhin zugelassen. Dadurch wird nun eine Policy eingesetzt, die keinen reellen Schutz vor XSS-Angriffen bietet. Am Ende wurde der CSP-Header wieder entfernt. Für eine striktere Policy-Definition oder eine Anpassung der Web-Anwendung wurden keine zusätzlichen Ressourcen investiert.

Die Einführung einer wirkungsvollen Content Security Policy ist anspruchsvoll und sollte im Einklang mit der Web-Entwicklung erfolgen. Dieser Beitrag zeigt die Entstehungsgeschichte von CSP und geht auf die Anwendung in der Praxis ein.

Entstehung und Entwicklung

Der erste Entwurf des Content Security Policy Level 1 wurde durch das W3C Konsortium am 15. November 2012 veröffentlicht. Vorerst wurde dies durch Browser-Hersteller als experimentelle Funktion mit dem Header X-Content-Security-Policy oder X-WebKit-CSP implementiert.

Das Ziel der CSP ist sowohl Web-Entwicklern als auch Webserver-Administratoren ein Werkzeug zur Mitigation von Injektion-Schwachstellen zur Verfügung zu stellen. Durch die Definition einer Policy wird der Web-Browser angewiesen welche Ressourcen der Web-Anwendungen, wie beispielsweise Bilder, Style-Sheets (CSS) oder Skripte, geladen und verarbeitet werden. CSP ist dabei als Bestandteil einer Defense-in-Depth-Strategie zu verstehen und darf nicht als Ersatz für eine Eingabevalidierung sowie der Kodierung von Ausgaben angesehen werden.

Der Header X-Content-Security-Policy wird in Mozilla Firefox ab Version 4 und in Microsoft Internet Explorer 10 unterstützt, gilt aber bereits als obsolet und sollte nicht mehr verwendet werden. Der Header Content-Security-Policy steht für CSP Level 1 und alle weiteren Levels. Er wird seit den Browser-Versionen Google Chrome 25, Mozilla Firefox 23, Safari 7 und Internet Explorer Edge unterstützt.

Über sogenannte Direktiven kann die Policy für den Anwendungszweck der Web-Anwendung massgeschneidert werden. Eine Direktive ist eine Anweisung für den Web-Browser, wie dieser verschiedene Ressourcen-Typen handhaben soll. Die Direktive default-src gilt als Standard für alle anderen Direktiven, solange diese nicht selbst spezifiziert sind. Es gibt Direktiven für die Steuerung von JavaScript, Bilder, Objekte und Style-Sheets (CSS). Jede Direktive wird mittels einer sogenannten Source Expression definiert. Die gültige Werte dafür sind unter anderem none, self, data: sowie eine oder mehrere Hosts/Domänen. Eine gute Übersicht dazu gibt es auf der Webseite Content Security Policy Reference.

Im Falle der Direktive für JavaScript namens script-src zeigte sich, dass die vorhandenen Source Expressions in der Praxis nicht ausreichend sind und so eine Hemmschwelle für die Implementierung von CSP darstellen. Mit Level 2, publiziert am 21. Juli 2015, wurde das Attribut nonce eingeführt um zusätzliche Flexibilität zu gewähren. Der nachfolgende Abschnitt zeigt dessen Anwendung – und Probleme.

Daneben wurde die Direktive frame-ancestors eingeführt. Das Ziel dieser Direktive ist es den HTTP-Header X-Frame-Options abzulösen. Die Expression none entspricht dabei dem Wert DENY des HTTP-Headers. Im Beitrag Inglorious Headers hat sich Veit Hailperin bereits ausführlich mit diesem Header auseinander gesetzt. Zurzeit sollte die Konfiguration zweigleisig erfolgen, über CSP und den Header selbst, da der CSP Level noch nicht durchgehend unterstützt wird.

Die Einführung von nonce konnte sich bisher in der Praxis nicht durchsetzen. Vor allem die Einbindung von JavaScript-Bibliotheken von Drittseiten erwies sich als ein Problem. Im Working Draft für den CSP Level 3 vom 21. Juni 2016 wird mit der Einführung der Source Expression strict-dynamic versucht dies zu lösen. Daneben wird als weitere Änderung die Direktive report-uri zu report-to umbenannt.

Anwendung beim Einsatz von JavaScript

Wenn bisher keine CSP im Einsatz ist, empfehlen wir jeweils mit der folgenden Direktive zu starten:

default-src ‘none’; script-src ‘self’; connect-src ‘self’; img-src ‘self’; style-src ‘self’;

Dadurch wird der Einsatz von Bildern, Styles (CSS) und JavaScript von der eigenen Domäne erlaubt. Bei der Nutzung von JavaScript bedeutet dies aber gleichzeitig, dass nur eingebundene Script-Dateien ausgeführt werden. Sogenannte Inline-Anweisungen, die in einem Script-Tag stehen, sind nicht erlaubt. Dies führt zum Problem, wenn eine Web-Anwendung so entwickelt wurde, dass direkt in HTML-Code mit dem Element script gearbeitet wird.

Damit nicht die ganze Webseite umgeschrieben werden muss, wird in der Regel die Direktive um die Expression unsafe-inline erweitert. Dadurch funktioniert die Web-Anwendung weiterhin wie gewohnt, ist aber wieder anfällig auf Reflected- oder Stored-XSS-Angriffe. Der Vorteil respektive der Schutzeffekt der Policy wird dadurch entfernt.

Der Einsatz von JavaScript ist bei vielen Web-Anwendungen nicht auf die eigene Domäne beschränkt. Es werden externe Bibliotheken in den Kontext der eigenen Seite eingebunden. Dadurch muss eine Whitelist von diesen Domänen in der Direktive script-src gepflegt werden. Die Pflege ist nicht trivial, und kann im schlimmsten Fall sogar zu einem CSP-Bypass führen. Dies wird in Lösungen der Minichallange von Cure53 namens H5SC Minichallenge 3: Sh*t, it’s CSP! eindrücklich aufgezeigt.

Mit der Einführung des Attributs nonce im CSP Level 2 gibt es nun die Möglichkeit eingebettete Script-Elemente zu nutzen. Das Prinzip von nonce ist, dass ein zufälliger nonce-Wert in die Direktive script-src geschrieben wird. Dies geschieht idealerweise durch die Web-Anwendung selbst. Jedes Script-Element, welches diesen Wert im Attribut nonce einsetzt, wird danach zugelassen. So können die legitimen Script-Elemente ausgeführt werden, XSS-Angriffe jedoch werden gestoppt.

Beim Einsatz von Bibliotheken, unter anderem JavaScript-CDNs wie jQuery, React.js oder AngularJS, ergibt sich mit der Verwendung von nonce ein neues Problem, das nachfolgend aufgezeigt wird. Das Attribut nonce wird entsprechend definiert:

Content-Security-Policy: script-src ‘nonce-i7bGtfs’

Danach wird eine Bibliothek in die Webseite eingebunden und korrekt mit dem passenden Wert im Attribut nonce versehen:

<script src=“https://cdn.example.com/script.js” nonce=“i7bGtfs”></script>

Da der korrekte Wert für nonce gesetzt ist, wird das Einbinden der Bibliothek erlaubt. Wenn nun aber in der Bibliothek selbst auch noch weitere Bibliotheken als Abhängigkeit nachgeladen werden oder ein Script-Element verwendet wird, führt dies zu einem Fehler, da dort der Wert für nonce nicht gesetzt ist. Im zweiten Fall betrifft es sogenannte parser-inserted Script-Elemente. Ein einfaches Beispiel für ein parser-inserted Element sieht so aus:

var scriptPath = ‘https://othercdn.not-example.net/dependency.js’
document.write(‘<script src=’ + scriptPath + ‘></script>’);

CSP Level 3 bringt mit der Expression strict-dynamic eine Lösung für das geschilderte Problem und vereinfacht die Verwendung von externen Bibliotheken. Es ergeben sich zwei Änderungen beziehungsweise Effekte, wenn strict-dynamic zusammen mit nonce verwendet wird:

  1. Die in der Direktive default-src oder script-src definierten Whitelists sowie die Verwendung von unsafe-inline werden verworfen.
  2. Nachladen von Abhängigkeiten in eingebundenen Bibliotheken sowie Skript-Elemente, die nicht parser-inserted sind, werden nun erlaubt.

Das bietet für den praktischen Einsatz zwei Vorteile. Der erste Effekt erlaubt ein rückwärts kompatibles Ausrollen von strict-dynamic. Die Policy

Content-Security-Policy: ‘unsafe-inline’ https: ‘nonce-abcdefg’ ‘strict-dynamic’

wird zu 'unsafe-inline' https: in Browsern, die CSP Level 1 unterstützen. Der Teil https: 'nonce-abcdefg' gilt im Falle von Level 2 Support und 'nonce-abcdefg' 'strict-dynamic' gilt in Browsern die CSP Level 3 implementiert haben. Der zweite Effekt spricht dem eingebundenen Skript das Vertrauen aus, eigene Abhängigkeiten einzubinden, ohne dass diese spezifisch in der Whitelist aufgeführt sein müssen.

Eine sehenswerte Präsentation zu CSP Bypasses und der Einführung von strict-dynamic ist der Talk von Lukas Weichselbaum und Michele Spagnuolo, beides Information Security Engineers bei Google, namens Breaking Bad CSP! an der diesjährigen Area41 2016. Die Slides des Talks wurden ebenfalls zur Verfügung gestellt.

Reporting

Der Header Content-Security-Policy weist den Web-Browser an die definierten Direktiven durchzusetzen. Dies kann und wird erfahrungsgemäss zu Problemen während der Einführung von CSP oder in der Entwicklungsphase einer Web-Anwendung führen. Daher gibt es einen zweiten CSP-Header namens Content-Security-Policy-Report-Only. Dieser rapportiert Verstösse gegen die Direktive, ohne diese zu blocken. Der Web-Browser sendet dabei eine Meldung an die definierte URL in der Direktive report-uri beziehungsweise zukünftig report-to.

Die Meldung beinhaltet die folgenden Elemente:

Diese Reports können hinsichtlich einer zu strikten Direktive, Verstösse gegen der Direktive durch Programmier-Fehler oder Nachlässigkeiten in der Web-Anwendung sowie potentiellen XSS-Angriffe ausgewertet werden. Der IT-Security-Researcher Scott Helme bietet unter der Website report-uri.io einen kostenlosen Dienst an, der zur Sammlung und Auswertung von CSP-Reports genutzt werden kann. Diese Webseite eignet sich gut für die ersten Gehversuche mit CSP, ohne dass eine Reporting-Infrastruktur aufgebaut werden muss oder bei öffentlich-verfügbaren Webseiten, die über keine sensitiven Daten verfügen. Bei sensitiven Webseiten sollte der Report-Service auf einem System, das der eigenen Kontrolle unterliegt, betrieben werden.

Wie schwer kann es sein?

Die Content Security Policy Level 3 bringt mit strict-dynamic eine Funktion, die für den produktiven Einsatz eine genügende Flexibilität mitbringt. Durch die Reporting-Funktion können zudem die Folgen einer Implementierung von CSP gut abgeschätzt werden. Diese Funktion ermöglicht es Schritt für Schritt zu testen, wie einzelne Direktiven konfiguriert werden können, so dass diese so strikt wie möglich sind, ohne aber die Funktionalität der Webseite zu behindern. Idealerweise wird bei der Web-Entwicklung selbst auf die Konformität einer Policy geachtet, die Nutzung von Inline Funktionen für CSS oder JavaScript sollte grundsätzlich unterlassen werden. Seit 2012 wird kontinuierlich an der CSP gearbeitet, um deren Funktionalität zu verbessern und die Implementation zu vereinfachen. CSP sollte kein Schreckgespenst mehr sein, das den Betrieb einer Webseite gefährdet, sondern sollte als weiterer Layer für eine sichere Web-Anwendung verstanden werden. Wir würden uns freuen, zukünftig mehr CSP-Header analysieren zu können, anstelle ein einfaches Der CSP-Header ist nicht gesetzt in die Checkliste einzutragen.

Über den Autor

Michael Schneider

Michael Schneider arbeitet seit dem Jahr 2000 in der IT. Im Jahr 2010 hat er sich auf die Informationssicherheit spezialisiert. Zu seinen Aufgaben gehören das Penetration Testing, Hardening und das Aufspüren von Schwachstellen in Betriebssystemen. Er ist bekannt für eine Vielzahl in PowerShell geschrieber Tools zum Finden, Ausnutzen und Beheben von Schwachstellen. (ORCID 0000-0003-0772-9761)

Links

Haben Sie Interesse an einem Penetration Test?

Unsere Spezialisten kontaktieren Sie gern!

×
HardeningKitty

HardeningKitty

Michael Schneider

KleptoKitty

KleptoKitty

Michael Schneider

Linux Hardening

Linux Hardening

Michael Schneider

Sie wollen mehr?

Weitere Artikel im Archiv

Sie brauchen Unterstützung bei einem solchen Projekt?

Unsere Spezialisten kontaktieren Sie gern!

Sie wollen mehr?

Weitere Artikel im Archiv