Area41 2024 - Ein Rückblick
Michael Schneider
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.
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.
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:
default-src
oder script-src
definierten Whitelists sowie die Verwendung von unsafe-inline
werden verworfen.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.
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:
document-uri
die Seite wo der Verstoss ausgelöst wurdereferrer
der Referrer der Seiteblocked-uri
die Basisadresse der geblockten URIviolated_directive
die spezifische Direktive, gegen die verstossen wurdeoriginal-policy
die komplette CSP-PolicyDiese 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.
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.
Unsere Spezialisten kontaktieren Sie gern!
Michael Schneider
Michael Schneider
Michael Schneider
Michael Schneider
Unsere Spezialisten kontaktieren Sie gern!