SecOps Toolkit

Content-Security-Policy-Generator und HTTP-Security-Header

Eine sauber definierte Content-Security-Policy (CSP) gehört zu den wirksamsten Maßnahmen gegen Cross-Site-Scripting (XSS) und Dateninjektion. Mit diesem Werkzeug bauen Sie den Header Schritt für Schritt auf, wenden Presets für gängige Dienste wie Google AdSense, Analytics oder Stripe an und exportieren die Konfiguration direkt für Nginx, Apache oder Cloudflare Workers.

Ein Validator prüft die Richtlinie in Echtzeit und weist auf riskante Einstellungen wie 'unsafe-inline' oder 'unsafe-eval' hin, bevor sie in Produktion gelangen.

Was ist die Content-Security-Policy und warum ist sie wichtig?

Die Content-Security-Policy (CSP) ist ein HTTP-Antwort-Header, mit dem ein Server dem Browser mitteilt, aus welchen Quellen Skripte, Stylesheets, Bilder, Schriftarten, Frames und Netzwerkverbindungen einer Seite geladen werden dürfen. Gelingt es einem Angreifer, Code in das HTML einzuschleusen, etwa über eine Cross-Site-Scripting-Schwachstelle (XSS), blockiert der Browser alles, was die Richtlinie nicht erlaubt. Die CSP ersetzt weder die Validierung von Eingaben noch das korrekte Escaping von Ausgaben auf dem Server, begrenzt aber den Schaden von Fehlern, die diesen Maßnahmen entgehen, erheblich.

So wertet der Browser eine Richtlinie aus

Jeder Ressourcentyp wird von einer eigenen Direktive gesteuert. Fehlt diese, greift der Browser auf default-src zurück. Vereinfacht gilt für jede Ressource:

  • erlaubt = Quelle ∈ Liste(spezifische Direktive), wenn die Direktive definiert ist.
  • erlaubt = Quelle ∈ Liste(default-src), wenn die spezifische Direktive fehlt.
  • Gibt es keine anwendbare Richtlinie, ist die Ressource uneingeschränkt erlaubt.

Drei Direktiven erben nicht von default-src: base-uri, form-action und frame-ancestors. Werden sie nicht gesetzt, bleiben sie unbeschränkt. Erhält eine Seite mehrere Richtlinien (etwa einen Header und ein Meta-Tag), gelten alle, und eine Ressource wird nur geladen, wenn sie jede einzelne erfüllt; das Ergebnis entspricht der Schnittmenge der Richtlinien.

Direktiven, die dieses Werkzeug konfiguriert

  • default-src: Rückfallrichtlinie für alle Ressourcentypen ohne eigene Direktive.
  • script-src: steuert JavaScript und ist die wichtigste Direktive gegen XSS.
  • style-src: Stylesheets und Inline-Style-Blöcke.
  • img-src und font-src: Bilder und Schriftarten.
  • connect-src: Ziele von fetch, XHR, WebSocket und Ähnlichem.
  • frame-src und frame-ancestors: welche Inhalte Ihre Seite einbetten darf und wer Ihre Seite einbetten darf (Schutz vor Clickjacking).
  • object-src, base-uri und form-action: schließen klassische Injektionswege über Plugins, <base>-Tags und Formulare.

Quellentypen

  • 'none': erlaubt nichts. Der richtige Wert für object-src.
  • 'self': nur derselbe Ursprung (Schema, Host und Port).
  • Konkrete Hosts wie https://js.stripe.com: die empfohlene Variante für Drittanbieter.
  • https: oder *: zu weit gefasst, erlaubt das Laden von nahezu jeder Website.
  • 'nonce-…' und 'sha256-…': erlauben einzelne Inline-Skripte, ohne 'unsafe-inline' zu verwenden.
  • 'strict-dynamic': vertraut Skripten, die von einem bereits per Nonce oder Hash erlaubten Skript nachgeladen werden.

Weitere Sicherheits-Header, die Sie ausrollen sollten

Strict-Transport-Security (HSTS) zwingt den Browser zur Nutzung von HTTPS. Der übliche Wert von einem Jahr ergibt sich aus max-age = 365 × 24 × 3600 = 31536000 Sekunden. Für die Aufnahme in die Preload-Liste der Browser sind zusätzlich includeSubDomains und preload erforderlich. Setzen Sie das nur um, wenn die gesamte Domain samt Subdomains über HTTPS funktioniert, denn ein Rückbau dauert lange.

X-Frame-Options (DENY oder SAMEORIGIN) schützt ältere Browser vor Clickjacking; frame-ancestors ist der moderne Nachfolger. X-Content-Type-Options: nosniff verhindert, dass der Browser den MIME-Typ einer Antwort umdeutet. Die Permissions-Policy deaktiviert Browserfunktionen wie Kamera, Mikrofon oder Standortfreigabe. Die Referrer-Policy begrenzt, welche Herkunftsinformationen bei ausgehenden Anfragen mitgesendet werden.

Schrittweise Einführung ohne Produktionsausfall

  1. Aktivieren Sie den Report-Only-Modus: Der Header Content-Security-Policy-Report-Only meldet Verstöße, ohne etwas zu blockieren.
  2. Werten Sie die Browserkonsole und die eingehenden Berichte aus und ergänzen Sie nur die legitimen Quellen, die fehlen.
  3. Entfernen Sie 'unsafe-inline' und 'unsafe-eval', indem Sie sie durch Hashes oder Nonces ersetzen und davon abhängigen Code überarbeiten.
  4. Wechseln Sie zum Header Content-Security-Policy im Erzwingungsmodus und lassen Sie das Monitoring aktiv.

Praxisbeispiele

  • Content-Website mit AdSense und Analytics: Die Presets ergänzen die benötigten Google-Hosts. Die Initialisierungs-Snippets sind Inline-Code, daher empfiehlt sich der Start im Report-Only-Modus.
  • Online-Shop mit Stripe: Das Preset erlaubt js.stripe.com in script-src und frame-src sowie api.stripe.com in connect-src.
  • Internes SaaS-Dashboard: Eine strikte Richtlinie mit default-src 'self', frame-ancestors 'none' und HSTS verkleinert die Angriffsfläche und erleichtert Sicherheitsaudits.
  • Statische Website hinter Cloudflare: Das Ergebnis lässt sich als Cloudflare Worker exportieren, der allen Antworten die Header hinzufügt, ohne den Ursprungsserver anzufassen.

Häufige Fehler

  • https: in script-src zu verwenden und das für sicher zu halten: Es erlaubt Skripte von jedem HTTPS-Host.
  • Öffentliche CDNs zuzulassen, die von Dritten kontrollierbare Inhalte ausliefern und zur Umgehung der Richtlinie dienen können.
  • base-uri, object-src und form-action zu vergessen, die nicht von default-src erben oder Vektoren offen lassen.
  • Sich beim Meta-Tag auf alles zu verlassen: Es unterstützt weder frame-ancestors noch report-uri oder sandbox.

Häufig gestellte Fragen

Was ist der Unterschied zwischen 'unsafe-inline' und Nonces oder Hashes?
'unsafe-inline' erlaubt jedes Inline-Skript und jeden Inline-Style der Seite, auch solche, die ein Angreifer einschleust, und hebt damit den Schutz vor XSS nahezu vollständig auf. Eine Nonce ist ein zufälliger Wert, der bei jeder Antwort neu erzeugt und sowohl im Header (nonce-...) als auch im nonce-Attribut jedes legitimen Script-Tags angegeben wird. Ein Hash (sha256-...) erlaubt einen bestimmten Inline-Block anhand seines Inhalts. Bei statischen Websites sind Hashes praktikabler, weil eine Nonce bei jeder Antwort neu generiert werden müsste. Sie können beides im Feld für zusätzliche Quellen der jeweiligen Direktive eintragen. Ist eine Nonce oder ein Hash vorhanden, ignorieren moderne Browser 'unsafe-inline' in dieser Direktive.
Wie teste ich eine CSP, ohne meine Website zu beschädigen?
Aktivieren Sie den Report-Only-Modus des Werkzeugs. Dabei wird der Header Content-Security-Policy-Report-Only erzeugt: Der Browser protokolliert in der Konsole jede Ressource, die gegen die Richtlinie verstoßen würde, blockiert sie aber nicht. Rufen Sie die wichtigsten Seiten auf, prüfen Sie die Meldungen, ergänzen Sie fehlende legitime Quellen und wiederholen Sie den Vorgang. Treten keine unerwarteten Verstöße mehr auf, wechseln Sie zum normalen Header Content-Security-Policy. Beachten Sie, dass frame-ancestors im Report-Only-Modus ignoriert wird.
Funktioniert die CSP mit Google AdSense und Google Analytics?
Ja, aber es sind Anpassungen nötig. Die Presets fügen die gängigsten Google-Hosts zu script-src, img-src, connect-src und frame-src hinzu. Die Standard-Snippets enthalten jedoch Inline-Code, der eine Nonce, einen Hash oder als letzte Option 'unsafe-inline' erfordert. Zudem kann AdSense je nach Auktion und Anzeigenformat Ressourcen von weiteren Domains laden. Starten Sie daher im Report-Only-Modus, werten Sie die Verstöße einige Tage aus und erweitern Sie die Richtlinie nur um die Ursprünge, die tatsächlich auftreten.
Kann ich ein Meta-Tag statt eines HTTP-Headers verwenden?
Das ist möglich, wenn Sie keinen Zugriff auf die Serverkonfiguration haben, etwa bei einfachem statischem Hosting, aber mit Einschränkungen. Das Meta-Tag http-equiv unterstützt die Direktiven frame-ancestors, report-uri und sandbox nicht, kennt keinen Report-Only-Modus und schützt nur, was nach der Verarbeitung des Tags durch den Browser geladen wird. Wann immer möglich, sollten Sie die Richtlinie als echten HTTP-Header über Nginx, Apache, ein CDN oder einen Worker ausliefern.
Sollte ich HSTS mit Preload aktivieren und welche Risiken gibt es?
HSTS verhindert, dass Browser HTTP verwenden, und das Preloading wirkt bereits beim ersten Besuch. Das ist sehr empfehlenswert, setzt aber voraus, dass die gesamte Domain und bei includeSubDomains alle Subdomains einwandfrei per HTTPS erreichbar sind. Die Anforderungen der Preload-Liste umfassen ein max-age von mindestens 31536000 Sekunden sowie includeSubDomains und preload. Ein Austrag aus der Liste dauert lange. Beginnen Sie daher mit einem kurzen max-age, erhöhen Sie ihn schrittweise und beantragen Sie das Preloading erst, wenn sicher ist, dass kein Dienst HTTP benötigt.