Sicherheit
Content-Security-Policy erklärt: Direktiven, unsafe-inline, Nonces und eine sichere Einführung
Die CSP ist der wirkungsvollste Security-Header – und der, bei dem am leichtesten etwas schiefgeht. Welche Direktiven zählen, wie Nonces und Hashes 'unsafe-inline' ersetzen und wie Sie die Richtlinie einführen, ohne Ihre Website lahmzulegen.
Auf dieser Seite
Eine Content-Security-Policy (CSP) ist ein Antwortheader, der dem Browser mitteilt, aus welchen Quellen eine Seite Skripte, Styles, Bilder, Frames und andere Ressourcen laden darf. Ihre Hauptaufgabe ist Schadensbegrenzung: Gelingt es einem Angreifer, über eine Cross-Site-Scripting-Lücke (XSS) ein <script> in Ihre Seite einzuschleusen, verhindert eine gute Richtlinie, dass der Browser es ausführt.
Der Haken: „Eine CSP“ und „eine gute CSP“ sind zwei sehr verschiedene Dinge. Ein Header voller Wildcards besteht jede Prüfung auf Vorhandensein und schützt so gut wie gar nicht. Dieser Leitfaden zeigt, woran Sie den Unterschied erkennen.
Wie eine Richtlinie aufgebaut ist
Eine Richtlinie ist eine Liste von Direktiven, die durch Semikolons getrennt sind. Jede Direktive nennt einen Ressourcentyp und die dafür erlaubten Quellen: Content-Security-Policy: default-src 'self'; img-src 'self' https://images.example-cdn.com; object-src 'none'.
Quellen können 'self' sein (Ihr eigener Origin), bestimmte Origins wie https://js.stripe.com, Schemata wie https: oder data:, Schlüsselwörter wie 'none' oder aber Nonces und Hashes, die weiter unten erklärt werden. Schlüsselwörter stehen in einfachen Anführungszeichen, Origins nicht.
Die wichtigsten Direktiven
default-src: der Rückfallwert für die meisten Ressourcentypen, die Sie nicht eigens aufführen.script-src: woher Skripte stammen dürfen. Diese Direktive ist es, die tatsächlich vor XSS schützt – sie verdient daher die größte Sorgfalt.style-src,img-src,font-src,connect-src(fetch, XHR, WebSockets),frame-srcundmedia-src: die übrigen Ressourcentypen.object-src 'none': blockiert Plugins wie<object>und<embed>, einen alten, aber noch immer genannten Weg, Skripte auszuführen.base-uri 'self'oder'none': verhindert, dass ein eingeschleustes<base>-Tag verändert, wohin relative Skript-URLs zeigen.frame-ancestors: welche Websites Ihre Seite in einen Frame einbetten dürfen – der zeitgemäße Ersatz für X-Frame-Options.form-action: wohin Formulare gesendet werden dürfen.upgrade-insecure-requests: weist den Browser an, Unterressourcen mithttp://über HTTPS zu laden.report-to/report-uri: wohin der Browser Berichte über Verstöße sendet.
Was eine Richtlinie schwächt
'unsafe-inline'
In script-src erlaubt 'unsafe-inline' jeden Inline-<script>-Block und jeden Inline-Event-Handler wie onclick. Genau das schleust ein XSS-Angriff ein – eine Richtlinie mit 'unsafe-inline' für Skripte hält ihn also kaum auf. Browser, die Nonces oder Hashes unterstützen, ignorieren 'unsafe-inline', sobald eines von beiden vorhanden ist; deshalb bleibt es mitunter neben einer Nonce als Rückfallwert für sehr alte Browser stehen.
'unsafe-eval'
'unsafe-eval' erlaubt eval(), new Function() und Zeichenketten als Argument von setTimeout. Damit werden aus Daten Code – und das ist riskant. Manche älteren Bibliotheken und Template-Engines sind darauf angewiesen; moderne Builds brauchen es in der Regel nicht.
Zu weit gefasste Quellen
*, https:, http: oder data: in script-src erlauben Skripte von praktisch überall – ein Angreifer kann sein Skript also auf jedem beliebigen HTTPS-Server ablegen. Beliebte CDNs sind ein subtileres Problem: Wer einen kompletten öffentlichen CDN-Host freigibt, erlaubt einem Angreifer, jede dort gehostete Bibliothek zu laden, einschließlich alter Versionen mit bekannten Umgehungsmöglichkeiten.
Report-Only allein
Content-Security-Policy-Report-Only meldet Verstöße, blockiert aber nichts. Als Einstieg ist das genau richtig – nur stehen bleiben dürfen Sie dort nicht.
Nonces und Hashes: der Ausweg aus 'unsafe-inline'
Eine Nonce ist ein Zufallswert, den Ihr Server für jede Antwort neu erzeugt. Sie tragen ihn in den Header ein – script-src 'nonce-R4nd0mV4lue' – und in jedes Script-Tag, dem Sie vertrauen: <script nonce="R4nd0mV4lue">. Der Browser führt nur Skripte aus, die die passende Nonce tragen. Ein eingeschleustes Skript kennt den Wert nicht und wird blockiert. Die Nonce muss unvorhersehbar und bei jeder Antwort eine andere sein; eine feste Nonce ist nicht besser als 'unsafe-inline'.
Ein Hash gibt genau ein bestimmtes Inline-Skript frei, und zwar über den SHA-256-, SHA-384- oder SHA-512-Hash seines Inhalts: script-src 'sha256-…'. Hashes eignen sich für statische Seiten, bei denen eine Nonce pro Antwort nicht praktikabel ist; jede Änderung am Skript verändert den Hash.
Mit 'strict-dynamic' dürfen Skripte, denen Sie per Nonce oder Hash vertrauen, weitere Skripte nachladen, und Browser, die das unterstützen, ignorieren Host-Positivlisten. Das macht eine sogenannte strikte CSP auch für Websites mit Tag-Managern und Widgets praktikabel: script-src 'nonce-{random}' 'strict-dynamic'; object-src 'none'; base-uri 'none'.
So liest sich Ihre CSP
Rudras kostenloser Sicherheitscheck zerlegt Ihre Content-Security-Policy Direktive für Direktive und meldet 'unsafe-inline', 'unsafe-eval', zu weit gefasste Skriptquellen sowie fehlendes object-src oder base-uri.
Ein Einführungsplan, der Ihre Website nicht lahmlegt
- Erfassen Sie, was die Seite lädt. Öffnen Sie die Entwicklertools auf Ihren wichtigsten Seiten – Startseite, Login, Checkout, Seiten mit eingebetteten Inhalten – und notieren Sie jeden Origin von Skripten, Styles, Schriften, Frames und APIs.
- Senden Sie eine Report-Only-Richtlinie. Beginnen Sie etwa mit
default-src 'self'; script-src 'self' 'nonce-{random}'; object-src 'none'; base-uri 'self'im HeaderContent-Security-Policy-Report-Only. Verstöße erscheinen in der Browserkonsole und an Ihrem Reporting-Endpunkt, falls Sie einen angegeben haben. - Beheben oder erlauben Sie jeden Verstoß. Lagern Sie Inline-Skripte in Dateien aus oder versehen Sie sie mit einer Nonce, ersetzen Sie Inline-
onclick-Handler durchaddEventListenerund ergänzen Sie genau die Drittanbieter-Origins, die Sie tatsächlich nutzen. - Setzen Sie die Richtlinie durch. Sobald in Ihren wichtigsten Abläufen keine Berichte mehr eingehen, ändern Sie den Header-Namen in
Content-Security-Policy. Parallel können Sie weiterhin eine strengere Report-Only-Richtlinie senden, um den nächsten Schritt zu testen. - Pflegen Sie die Richtlinie. Jedes neue Widget, Analyse-Tool und jeder neue Zahlungsanbieter erfordert eine Anpassung. Prüfen Sie nach jeder Ergänzung erneut.
Setzen Sie den Header auf dem Server, im CDN oder im Framework und nach Möglichkeit nicht in einem <meta>-Tag: Eine Richtlinie im Meta-Tag kann weder frame-ancestors noch Reporting oder den Report-Only-Modus nutzen.
Was Rudra an Ihrer Richtlinie prüft
Der kostenlose Website-Sicherheitscheck liest die CSP, die Ihre Seite tatsächlich sendet, und zeigt die ausgewerteten Direktiven als Beleg an. Er meldet eine fehlende Richtlinie, eine Richtlinie, die nur als Report-Only gesendet wird, eine Richtlinie, die Skripte überhaupt nicht einschränkt (weder script-src noch default-src), 'unsafe-inline' in der Skript-Richtlinie (nicht gemeldet, wenn eine Nonce oder ein Hash vorhanden ist), 'unsafe-eval', zu weit gefasste Skriptquellen wie * oder https: (sofern Sie nicht 'strict-dynamic' mit Nonce oder Hash verwenden) und – als informative Hinweise – ein fehlendes object-src 'none', ein fehlendes base-uri sowie Inline-Styles. frame-ancestors erkennt er als Schutz vor Clickjacking an, solange der Wert weder * noch ein bloßes Schema ist.
Ein Prüftool kann Ihnen sagen, was Ihre Richtlinie erlaubt. Ob Ihre Seiten damit noch funktionieren, kann es nicht sagen – das zeigt nur ein Test Ihrer echten Abläufe im Report-Only-Modus.
Häufig gestellte Fragen
Verhindert eine Content-Security-Policy XSS?
Die zugrunde liegende Lücke behebt sie nicht, aber eine strikte Richtlinie verhindert, dass die meisten eingeschleusten Skripte ausgeführt werden, und begrenzt so den Schaden. Ausgaben maskieren und Eingaben validieren müssen Sie trotzdem.
Ist 'unsafe-inline' in style-src ein Problem?
Es ist deutlich weniger gravierend als in script-src. Eingeschleuste Styles lassen sich bei manchen Angriffen dennoch missbrauchen – es zu entfernen ist also eine sinnvolle Härtung, kümmern Sie sich aber zuerst um die Skript-Richtlinie.
Kann ich auf jeder Seite dieselbe Nonce verwenden?
Nein. Eine Nonce muss zufällig und für jede Antwort einzigartig sein. Eine feste oder wiederverwendete Nonce kann ein Angreifer kopieren – sie bietet keinen Schutz.
Wie lange sollte Report-Only laufen, bevor ich die Richtlinie durchsetze?
Lange genug, um Ihre tatsächlichen Traffic-Muster abzudecken – oft ein bis zwei Wochen –, einschließlich Login, Checkout und aller Seiten mit eingebetteten Drittanbieter-Inhalten. Setzen Sie die Richtlinie durch, sobald die Berichte nur noch Rauschen zeigen, etwa durch Browsererweiterungen.