Frage an Claude:
Sicherstellen, dass die CSP effektiv gegen XSS-Angriffe abwehrt
Eine wirksame CSP gegen XSS-Angriffe braucht mehrere Bausteine. Hier die wichtigsten Punkte:
1. script-src ist der wichtigste Hebel
Content-Security-Policy: script-src 'self' 'nonce-{RANDOM}' 'strict-dynamic';
Vermeiden:
'unsafe-inline'– hebt den XSS-Schutz praktisch komplett auf'unsafe-eval'– erlaubteval(),new Function(), etc.- Breite Whitelists wie
https://*.cdn.com– oft umgehbar über JSONP-Endpoints, offene Redirects oder alte Bibliotheksversionen auf derselben Domain (siehe CSP-Bypass-Listen)
2. Nonce- oder Hash-basierter Ansatz statt Whitelist
Whitelist-basierte CSPs gelten mittlerweile als unsicher, weil sich auf vielen CDNs (Google Hosted Libraries, Cloudflare, etc.) Skript-Gadgets finden, die eine Umgehung erlauben. Besser:
- Nonce: Pro Request ein zufälliger, kryptografisch sicherer Wert (
nonce-xxx), der bei jedem<script>-Tag serverseitig eingefügt wird - Hash: SHA256-Hash des exakten Skriptinhalts (nur praktikabel bei statischen/wenigen Inline-Skripten)
'strict-dynamic'zusammen mit Nonce/Hash erlaubt, dass von vertrauenswürdigen Skripten dynamisch nachgeladene Skripte automatisch vertraut werden – ohne dass man jede Domain einzeln whitelisten muss
3. Weitere wichtige Direktiven
default-src 'self';
object-src 'none';
base-uri 'self';
frame-ancestors 'self';
form-action 'self';
object-src 'none'– blockiert Flash/Plugin-basierte XSS-Vektorenbase-uri 'self'– verhindert Manipulation von<base href>, was sonst relative Pfade kapern kannframe-ancestors– schützt zusätzlich vor Clickjacking (Ersatz fürX-Frame-Options)
4. Typische Schwachstellen der eigenen CSP prüfen
- JSONP-Endpoints auf erlaubten Domains (
callback=alert(1)) - Angular/Vue mit
unsafe-eval– manche Frameworks brauchen das standardmäßig, es gibt aber CSP-kompatible Build-Modi - Base-Tag-Injection, wenn
base-urifehlt - Wildcard-Subdomains (
*.example.com), falls Subdomain-Takeover möglich ist
5. Testen und überwachen
Content-Security-Policy-Report-OnlyHeader parallel einsetzen, um Verstöße zu loggen, bevor man scharf schaltetreport-uri/report-toDirektive für Reporting-Endpoint nutzen- Tools wie CSP Evaluator (Google) zur automatisierten Prüfung
Wichtig: CSP ist eine zusätzliche Schutzschicht, kein Ersatz
CSP ist „defense in depth“ – es ersetzt nicht:
- Kontextgerechtes Escaping/Encoding von Nutzereingaben (HTML-, JS-, URL-Kontext)
- Serverseitige Validierung von Eingaben
- Sichere Verwendung von APIs wie
textContentstattinnerHTML
Wenn du magst, kann ich mir eine konkrete CSP für deinen Stack (z. B. React/Angular/klassisches Server-Rendering) genauer ansehen – sag mir einfach, wie eure Inline-Skripte/Styles aktuell eingebunden sind.
<link rel=“stylesheet“ type=“text/css“ media=“all“ href=“https://www.suederlaender.de/Sauerland/wp-content/themes/twentyten/style.css“ />
Dachte 3 s nach
Das sieht nach einem klassischen WordPress-Setup aus (Theme „twentyten“). WordPress bringt für CSP ein paar spezifische Herausforderungen mit sich, hier die wichtigsten Punkte für deinen Fall:
1. style-src für dieses konkrete Stylesheet
Content-Security-Policy: style-src 'self' https://www.suederlaender.de;
Da das Stylesheet von der eigenen Domain kommt, reicht 'self' bereits aus – eine explizite Domain-Nennung ist nur nötig, falls Assets über eine CDN-Subdomain oder externe Domain ausgeliefert werden.
2. WordPress-typische CSP-Fallstricke
- Inline-Styles: WordPress und viele Plugins/Themes (auch ältere wie „twentyten“) schreiben oft
style="..."direkt ins Markup oder generieren<style>-Blöcke inline (z. B. für Custom-Header-Farben, Widgets). Das bricht mit einer striktenstyle-src 'self'-Policy.- Lösung: Entweder Nonces für WP-generierte
<style>-Blöcke einbauen (per Filter aufwp_head), oder Hashes für statische Inline-Styles verwenden, oder pragmatisch'unsafe-inline'nur fürstyle-src(nicht fürscript-src!) zulassen – das Risiko ist bei CSS deutlich geringer als bei JS, aber CSS-basierte Datenexfiltration ist theoretisch möglich.
- Lösung: Entweder Nonces für WP-generierte
- Inline-Scripts:
wp_head()/wp_footer()fügen oft Inline-<script>-Blöcke ein (z. B. füremoji-release.min.js-Konfiguration, Google Fonts, Analytics-Snippets). Hier brauchst du zwingend Nonces oder Hashes. - Plugins: jedes aktive Plugin kann zusätzliche externe Domains (Fonts, Skripte, iFrames) einbinden – die CSP muss diese explizit whitelisten oder die Plugins müssen darauf geprüft werden.
- jQuery & Legacy-Theme-JS: alte Themes wie „twentyten“ nutzen teils
eval()-artige Patterns in Legacy-jQuery-Plugins – prüfen, ob'unsafe-eval'wirklich nötig ist oder ob es umgangen werden kann.
3. Praktisches Vorgehen für WordPress
- CSP zunächst als
Content-Security-Policy-Report-Onlyper Plugin (z. B. „Headers Security Advanced & HSTS WP“ oder manuell über.htaccess/functions.php) einspielen - Reports sammeln (
report-uri), um zu sehen, welche Domains/Inline-Blöcke tatsächlich gebraucht werden - Erst danach zur echten
Content-Security-Policywechseln
Willst du, dass ich dir eine konkrete Policy für ein WordPress-Setup mit functions.php-Snippet zum Setzen der Header und zum Nonce-Handling in wp_head/wp_footer baue?
mach mal
WordPress CSP-Implementation mit Nonce-Handling
1. functions.php – Header setzen + Nonce generieren
php
<?php
/**
* CSP mit Nonce-basiertem script-src / style-src
* In functions.php des aktiven Themes (oder besser: eigenes Must-Use-Plugin)
*/
// Nonce einmal pro Request generieren und global verfügbar machen
function csp_generate_nonce() {
if ( ! defined('CSP_NONCE') ) {
define('CSP_NONCE', base64_encode(random_bytes(16)));
}
return CSP_NONCE;
}
// CSP-Header setzen (vor jedem Seitenaufruf)
add_action('send_headers', function() {
$nonce = csp_generate_nonce();
$csp = "default-src 'self'; " .
"script-src 'self' 'nonce-{$nonce}' 'strict-dynamic'; " .
"style-src 'self' 'nonce-{$nonce}'; " .
"img-src 'self' data: https:; " .
"font-src 'self' data:; " .
"object-src 'none'; " .
"base-uri 'self'; " .
"form-action 'self'; " .
"frame-ancestors 'self'; " .
"report-uri /wp-json/csp/v1/report";
// Zunächst im Report-Only-Modus testen:
header("Content-Security-Policy-Report-Only: {$csp}");
// Nach erfolgreichem Testlauf umstellen auf:
// header("Content-Security-Policy: {$csp}");
});
2. Nonce auf WordPress-generierte Inline-Scripts anwenden
WordPress fügt an vielen Stellen automatisch Inline-<script>-Blöcke ein (z. B. für wp_add_inline_script). Der Filter script_loader_tag fängt das ab:
php
// Nonce zu allen <script>-Tags hinzufügen
add_filter('script_loader_tag', function($tag, $handle) {
$nonce = csp_generate_nonce();
if (strpos($tag, 'nonce=') === false) {
$tag = str_replace(' src=', " nonce=\"{$nonce}\" src=", $tag);
}
return $tag;
}, 10, 2);
// Dasselbe für <style>-Tags
add_filter('style_loader_tag', function($tag, $handle) {
$nonce = csp_generate_nonce();
if (strpos($tag, 'nonce=') === false) {
$tag = str_replace('<link ', "<link nonce=\"{$nonce}\" ", $tag);
}
return $tag;
}, 10, 2);
Wichtig: Echte Inline-<script>-Blöcke (nicht <script src="...">), die z. B. per wp_add_inline_script() oder direkt im Theme via echo '<script>...' eingebunden werden, muss man manuell mit dem Nonce versehen:
php
// Beispiel: eigenes Inline-Script im Theme mit Nonce ausstatten
function my_inline_script() {
$nonce = csp_generate_nonce();
echo "<script nonce=\"{$nonce}\">console.log('safe inline script');</script>";
}
add_action('wp_footer', 'my_inline_script');
3. Reporting-Endpoint einrichten (REST API)
php
// Registriert /wp-json/csp/v1/report zum Sammeln von Verstößen
add_action('rest_api_init', function() {
register_rest_route('csp/v1', '/report', [
'methods' => 'POST',
'callback' => function(WP_REST_Request $request) {
$body = $request->get_body();
$log_file = WP_CONTENT_DIR . '/csp-violations.log';
file_put_contents(
$log_file,
date('c') . ' ' . $body . PHP_EOL,
FILE_APPEND | LOCK_EX
);
return new WP_REST_Response(null, 204);
},
'permission_callback' => '__return_true',
]);
});
⚠️ In Produktion: Rate-Limiting auf den Endpoint legen (sonst potenzieller DoS-Vektor durch massenhafte Fake-Reports), und Log-Datei nicht öffentlich zugänglich machen (.htaccess-Schutz oder außerhalb des Web-Roots ablegen).
4. Vorgehen in der Praxis
- Report-Only aktivieren, ein paar Tage/Wochen normalen Traffic beobachten
csp-violations.logauswerten – welche Domains/Inline-Blöcke schlagen fehl?- Häufige Kandidaten bei WP: Google Fonts, Gravatar (
secure.gravatar.com), Emoji-Skripte, Analytics/Tracking-Plugins, Elementor/Page-Builder-Inline-Styles
- Häufige Kandidaten bei WP: Google Fonts, Gravatar (
- Policy entsprechend ergänzen (Domains whitelisten, weitere Nonce-Stellen identifizieren)
- Erst dann auf echten
Content-Security-Policy-Header umstellen (Zeile im Code oben austauschen)
5. Falls zu viele Inline-Styles das Nonce-Verfahren unpraktikabel machen
Bei stark Plugin-lastigen WP-Installationen mit vielen dynamischen Inline-Styles ist ein pragmatischer Kompromiss verbreitet:
style-src 'self' 'unsafe-inline';
script-src 'self' 'nonce-{RANDOM}' 'strict-dynamic';
Also 'unsafe-inline' nur für Styles (deutlich geringeres Risiko als bei Scripts), während script-src strikt bleibt. Das ist ein bewusster Trade-off zwischen Sicherheit und Wartungsaufwand – die eigentliche XSS-Schutzwirkung kommt fast ausschließlich aus der script-src-Härtung.
Soll ich dir noch zeigen, wie man das für ein Caching-Plugin (z. B. WP Super Cache, W3 Total Cache) anpasst? Da der Nonce pro Request einzigartig sein muss, verträgt sich das nicht trivial mit vollständig gecachtem HTML – das ist ein häufiger Stolperstein bei WordPress-CSP-Setups.
Komme ggf. später drauf zurück …
