Content-Security-Policy (CSP): HTTP-Security-Header zum Schutz vor XSS- und Code-Injection-Angriffen
Der HTTP-Security-Header Content-Security-Policy (CSP) dient zum Erkennen von sowie dem Schutz vor schädlichen Cross-Site-Scripting (XSS), Clickjacking und anderen Code-Injection-Angriffen. Hierfür wird dem Webbrowser mitgeteilt, welche Daten (JavaScript, Grafiken, CSS etc.) von welchen Quellen geladen und ausgeführt werden dürfen. Des Weiteren besteht die Möglichkeit unverschlüsselte und somit unsichere Verbindungen via HTTP auf verschlüsselte HTTPS-Verbindungen zu upgraden bzw. generell zu blocken.
Wie ihr die Content-Security-Policy auf eurer Website bzw. in eurer Webandwendung einsetzt, erfahrt ihr in diesem Beitrag.
Content-Security-Policy - Beschreibung & Funktionsweise
Mit der Content-Security-Policy kann, wie einleitend bereits erwähnt, gesteuert werden, welche Daten bzw. "Datentypen" der Webbrowser laden und ausführen darf. Zudem lässt sich festlegen, aus welchen Quellen diese Daten stammen müssen. Hierzu werden die erlaubten Daten per "Whitelisting" als vertrauenswürdig ausgewiesen.
Um den Webbrowser die zu verwendende Policy mitzuteilen, sendet der Webserver innerhalb der HTTP-Antwort den entsprechenden HTTP-Header mit:
Das o.a. Beispiel enthält die einfache Standard-Policy default-src 'self'
. Diese Policy weist den Webbrowser an, Daten nur von der selben Quelle/Herkunft (Origin) zu laden, wie die Webseite selbst. Außerdem wird das Ausführen von Inline-JavaScript unterbunden.
Beispiel - CSP in Aktion
An einem einfachen Beispiel soll die Funktionsweise verdeutlich werden. Angenommen ihr ruft eine Webseite mit folgendem Inhalt (nur ein Ausschnitt) auf:
Ohne Einsatz der Content-Security-Policy würde das Inline-JavaScript ganz normal ausgeführt werden und ihr würdet in eurer Webbrowser-Konsole die entsprechende Ausgabe sehen. Soll das Ausführen des Inline-JavaScripts unterbunden werden, so kann die o.a. default-src 'self'
-Policy Verwendung finden. Anschließend führt der Webbrowser das eingebette JavaScript nicht mehr aus. Erkennbar ist das daran, dass ihr anstelle der Ausgabe JavaScript executed!
eine Fehlermeldung angezeigt bekommt.
Generell gibt es diverse Policy-Direktiven mit der ihr eure Policy feingranular einstellen könnt. Beispielsweise lässt sich einstellen, dass Daten standardmäßig die gleiche Herkunft, wie die aufgerufene Webseite haben müssen. Grafiken hingegen können aus allen Quellen geladen werden. CSS-Dateien sollen wiederum nur von einer bestimmten Domain erlaubt sein. Als Policy könnte das dann wie folgt aussehen:
default-src 'self'; img-src *; style-src assets.my-domain.de;
Enforce- vs. Report-Modus
Die Content-Security-Policy kann in zwei Modi verwendet werden - ich nenne sie mal "Enforce"- und "Report"-Modus. Der "Report"-Modus bietet sich an, wenn man die Content-Security-Policy auf seiner Webseite neu einführen bzw. Änderungen an der bestehenden Policy vornehmen möchte. In diesem Modus werden die Policy-Anweisungen vom Webbrowser nicht angewendet, aber Verstöße werden an eine optional anzugebende URL gesendet bzw. alternativ in der Konsole des Webbrowsers ausgegeben. Mit dem "Report"-Modus kann eine Policy getestet werden ohne aufgrund einer Fehlkonfiguration die Webseite versehentlich "lahm" zu legen.
Die Aktivierung des "Report"-Modus unterscheidet sich zum "Enforce"-Modus nur im anzupassenden Header-Namen:
Im Webbrowser würde dann in der Konsole ein Hinweis erscheinen:
Weiterführende Informationen zum "Report"-Modus bzw. dem Header: Content-Security-Policy-Report-Only
Policy-Direktiven im Detail
Da es recht viele Policy-Direktiven gibt, beschränke ich mich im Folgenden auf die gebräuchlichsten Direktiven. Ein Liste aller Direktiven und möglichen Werte findet ihr hier: CSP-Direktiven.
default-src
Diese Angabe sollte prinzipiell immer verwendet werden, da sie als Fallback für alle anderen nicht explizit angegebenen "Fetch"-Direktiven gilt.
script-src
Quellen für Script-Dateien definieren und z.B. festlegen, ob Inline-JavaScript erlaubt
img-src
Quellen für Grafik-Dateien definieren und z.B. festlegen, ob Inline-Grafiken via Data-URL erlaubt
style-src
Quellen für CSS-Dateien definieren und z.B. festlegen, ob Inline-CSS erlaubt
font-src
Quellen für Font-Dateien definieren
form-action
Quellen für erlaubte "Submit"-URLs von Formularen definieren
frame-anchestors
Quellen definieren, die die eigene Webseite z.B. mittels Frames einbinden dürfen
block-all-mixed-content
verhindert das Laden von unverschlüsselten HTTP-Ressourcen, wenn Webseite mittels HTTPS geladen wurde
upgrade-insecure-requests
behandelt alle unverschlüsselten HTTP-URLs als HTTPS-URLs - die Ressourcen werden also immer per HTTPS geladen auch wenn sie im Quelltext per HTTP ausgewiesen sind
Inline-JavaScript erlauben
Nicht immer lässt sich Inline-JavaScript vermeiden. In solchen Fällen gibt es die folgenden 3 Möglichkeiten:
- unsafe-inline
- Hashes
- Nonces
In der einfachsten und somit unsichersten Variante, erlaubt man einfach jegliches Inline-JavaScript:
script-src 'unsafe-inline'
Besser ist es aber nur bewusst ausgewählte JavaScript-Blöcke zu erlauben. Dazu können Hashes oder Nonces verwendet werden. Hashes eigenen sich für statische JavaScript-Blöcke, die sich nicht (dynamisch) ändern. In der Konsole von Chrome wird bspw. der Hash zu einem geblockten JavaScript-Block direkt angezeigt und man kann diesen ganz einfach kopieren und in die Policy integrieren:
script-src 'sha256-abcdefghi'
Für JavaScript-Blöcke die sich ändern können, sind Nonces die richtige Wahl. Hierfür wird einem Script-Block eine generierte Nonce zugewiesen:
Analog zu Hashes müssen die erlaubten Nonces in die Policy eingefügt werden:
script-src 'nonce-djksdjiwdsjdis'
Webbrowser-Unterstützung
Die Content-Security-Policy wird von allen gängigen Webbrowsern unterstützt (siehe caniuse.com).
Content-Security-Policy übertragen
Um den Webserver anzuweisen, den Content-Security-Policy-Header zum Client mitzusenden, muss dieser entsprechend konfiguriert werden.
Apache:
In der Konfigurationsdatei von Apache oder in der .htaccess
ist folgende Anweisung zu hinterlegen:
nginx:
Analog dazu ist für nginx in der Konfigurationsdatei Folgendes einzufügen:
Alternative Möglichkeit zur Übertragung
Grundsätzlich besteht auch die Möglichkeit die Content-Security-Policy anstatt per HTTP-Header mittels meta
-Tag auszuliefern:
Content-Security-Policy von codingblatt.de
Folgende Policy-Direktiven verwende ich hier im Blog:
- default-src 'none'
- font-src 'self'
- img-src 'self'
- style-src 'self'
- block-all-mixed-content
- base-uri 'none'
- frame-ancestors 'none'
- form-action 'none'
Standardmäßig blockiere ich alles, um dann selektiv das Laden von Schriftarten, Grafiken und CSS ausschließlich von der Domain https://www.codingblatt.de
zu erlauben. Das Ausführen von JavaScript wird hierdurch auch generell im Blog unterbunden.
Fazit
Die Content-Security-Policy ist ein weiterer Baustein zur Absicherung der eigenen Website bzw. Webanwendung vor schädlichen Angriffen. Ich würde sagen, dass es sich aktuell um den "mächtigsten" HTTP-Security-Header handelt, da durch die verschiedenen Policy-Direktiven diverse Angriffstypen- & szenarien abgewehrt bzw. erschwert werden können.