CSP, SameSite & Co: was die kleinen Response-Header tatsächlich leisten
Eine Content Security Policy stoppt den Grossteil der klassischen XSS- und Datenexfiltrations-Angriffe. SameSite-Cookies entschärfen CSRF. Richtig konfiguriert bilden sie eine zweite Verteidigungsschicht, die nur dann sichtbar wird, wenn die erste versagt. Wie eine strikte, aber praxistaugliche Header-Konfiguration aussieht.
Problem
Die meisten Angriffe auf authentifizierte Nutzer laufen nicht gegen den Anmelde-Mechanismus, sondern gegen den schon angemeldeten Browser. Cross-Site Scripting (XSS) schleust fremdes JavaScript in die Seite; Cross-Site Request Forgery (CSRF) nutzt das existente Session-Cookie, um beliebige state-verändernde Aktionen auszulösen; Clickjacking legt eine transparente Seite über die echte und lässt den Nutzer versehentlich klicken.
Alle drei Angriffsklassen sind seit Jahren bekannt. Sie leben nicht, weil sich Entwickler nicht darum kümmern, sondern weil die Schutzmechanismen viele kleine Details haben und ein einzelner Fehler die ganze Wirkung nimmt. Ein Beispiel: eine sonst saubere CSP mit einem einzigen unsafe-inline im script-src hebt den XSS-Schutz praktisch komplett aus.
Kurze Antwort
Drei Header-Familien leisten zusammen einen Grossteil der Arbeit:
- Content Security Policy (CSP) schränkt ein, welche Ressourcen die Seite laden darf. Mit
nonce-basierten Scripts und ohneunsafe-inlinewird eine injizierte<script>-Tag-Instanz ineffektiv, weil ihr der aktuelle Nonce fehlt. - Cookie-Attribute SameSite und Secure verhindern, dass Session-Cookies bei Cross-Site-Requests automatisch mitgehen; damit schlagen CSRF-Angriffe ins Leere, weil der Browser das Cookie gar nicht mitschickt.
- X-Content-Type-Options, Referrer-Policy, X-Frame-Options/frame-ancestors decken Clickjacking, MIME-Sniffing-Angriffe und Referer-Leaks.
Kein einzelner Header ersetzt saubere Applikationshygiene. Zusammen bilden sie die zweite Schicht, die dann wirkt, wenn die erste (Input-Validierung, Output-Escaping) versagt.
Tiefgang
CSP: die harte Schicht gegen XSS
Ein CSP-Header listet erlaubte Herkünfte pro Ressourcentyp auf. Ein produktionsreifes Minimum:
Content-Security-Policy:
default-src 'none';
script-src 'nonce-abc123' 'strict-dynamic';
style-src 'self';
img-src 'self' data:;
connect-src 'self';
font-src 'self';
base-uri 'none';
form-action 'self';
frame-ancestors 'none';
upgrade-insecure-requestsDie wichtigsten Direktiven:
default-src 'none'startet explizit ohne Erlaubnis. Alles, was nicht weiter unten explizit freigegeben wird, ist verboten.script-src 'nonce-abc123' 'strict-dynamic': JavaScript läuft nur, wenn der script-Tag einen Nonce mit passendem Wert trägt. Der Nonce ändert sich pro Response und wird serverseitig in die HTML-Seite injiziert. Ein injizierter Script-Tag ohne diesen Nonce wird vom Browser ignoriert.strict-dynamiclässt dynamisch per JavaScript eingefügte Scripts zu, solange ein nonce-valider Script sie erzeugt hat.style-src 'self': Styles nur aus der eigenen Origin. Wer inline-Styles braucht, nutzt'nonce-…'(selbes Prinzip), nichtunsafe-inline.base-uri 'none'verhindert, dass ein injiziertes<base>-Tag relative URLs umleitet.form-action 'self'verhindert, dass ein Formular nach extern posten kann.frame-ancestors 'none'ersetztX-Frame-Options: DENYund verhindert Clickjacking.upgrade-insecure-requests: HTTP-Ressourcen werden automatisch auf HTTPS umgeschrieben.
Was hier bewusst fehlt: 'unsafe-inline' und 'unsafe-eval'. Beide machen CSP effektiv wirkungslos gegen XSS. Legacy-Anwendungen, die sie benötigen, sollten in einer Übergangsphase mit Content-Security-Policy-Report-Only messen, was geblockt würde, und die Codebasis stückweise auf Nonce-fähig oder Hash-fähig umstellen.
SameSite: CSRF-Schutz ohne eigenes Token
Cookies mit SameSite=Strict werden vom Browser bei Cross-Site-Requests (also Requests, deren Absender-Site sich von der Ziel-Site unterscheidet) nicht mitgeschickt. Ein Angreifer, der eine bösartige Seite auf evil.example.org hostet und von dort einen POST auf bank.example.de auslöst, bekommt keine Session-Cookies mehr mitgegeben, der Angriff scheitert an fehlender Authentifizierung.
Die Ausprägungen:
- Strict: Cookie wird nur bei same-site Requests mitgeschickt, inklusive Navigation. Stärkster Schutz. Nebenwirkung: wer auf einen Login-Link in einer E-Mail klickt, ist auf der Ziel-Seite nicht eingeloggt, weil die Navigation als cross-site gilt.
- Lax (seit 2020 Browser-Default): Cookie wird bei same-site Requests und bei Top-Level-Navigation (GET-Requests) mitgeschickt, aber nicht bei cross-site POST/PUT/DELETE. Guter Kompromiss für die meisten Anwendungen.
- None: Cookie wird immer mitgeschickt; nur zulässig in Kombination mit
Secure. Sollte bewusst eingesetzt werden, niemals als Default.
Produktive Empfehlung: SameSite=Lax für Session-Cookies in typischen Web-Anwendungen, SameSite=Strict für hochschutzbedürftige Anwendungen mit eigenen Login-Pfaden, die keine Deep-Links aus Mails erwarten.
Die begleitenden Header
[Strict-Transport-Security`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security) (HSTS): erzwingt HTTPS für die Domain. Nach dem ersten Besuch bleibt HSTS im Browser gepinnt; spätere HTTP-URLs werden automatisch nach HTTPS umgeschrieben, bevor sie den Netzwerk-Stack erreichen.
Strict-Transport-Security: max-age=63072000; includeSubDomains; preloadWer preload setzt und die Domain bei hstspreload.org registriert, wird in der HSTS-Liste des Browsers mitausgeliefert, ab dann ist auch der allererste Besuch pro HTTPS abgesichert.
X-Content-Type-Options: nosniff schaltet den Browser-eigenen MIME-Sniffer ab. Der Sniffer kann ein hochgeladenes Dokument als HTML interpretieren, selbst wenn der Server es als text/plain ausliefert, und damit eingebettetes JavaScript ausführen. Mit nosniff hält sich der Browser an den Content-Type.
Referrer-Policy: steuert, welcher Teil der aktuellen URL beim Verlassen der Seite im Referer-Header an die Zielseite geht. no-referrer ist die konservativste Wahl; strict-origin-when-cross-origin ein praxistauglicher Kompromiss.
Permissions-Policy (früher Feature-Policy): schaltet Browser-APIs für die eigene Seite und für eingebettete Frames ab. Wer keine Kamera, kein Mikrofon, keinen Fullscreen-Modus braucht, schaltet sie ab, und verkleinert die Angriffsfläche für spätere API-Lücken.
Cross-Origin-Opener-Policy: same-origin trennt die Window-Group der Seite von Popup-Fenstern und verhindert, dass der Popup-Opener Cross-Origin-Zugriffe aufmacht.
Cross-Origin-Resource-Policy: same-origin erlaubt den Resource-Embed nur für die eigene Origin. Verhindert, dass die Seite in einem fremden Kontext als Ressource eingebunden wird.
Cross-Origin-Embedder-Policy: require-corp schaltet Spectre-artige Timing-Angriffe auf SharedArrayBuffer und High-Resolution-Timer ab, nur sinnvoll, wenn die Seite selbst diese APIs nutzt.
Die Rolle des Cookies mit Secure und HttpOnly
Neben SameSite gehören zwei weitere Attribute in jeden Session-Cookie:
Secure: Cookie wird nur über HTTPS-Verbindungen mitgeschickt. Fehlt das Attribut, leckt ein einziger HTTP-Redirect (durch einen Coffee-Shop-Hotspot, einen Proxy-Fehler, einen falschen Link) das Cookie im Klartext.HttpOnly: JavaScript in der Seite hat keinen Zugriff auf das Cookie. Damit bleibt das Cookie auch dann geschützt, wenn eine XSS-Lücke existiert, der Angreifer kann keinen Cookie-Wert ablesen.
Ein produktionsreifes Session-Cookie sieht so aus:
Set-Cookie: session=abc; Path=/; HttpOnly; Secure; SameSite=Lax; Max-Age=7200Abgelehnte Alternativen und Mythen
"CSP mit unsafe-inline ist ja auch etwas." Nicht in der Praxis. Der XSS-Schutz steht und fällt mit dem Ausschluss von unsafe-inline. Wer unsafe-inline braucht, hat eine Migrations-Aufgabe, keinen konfigurierbaren Schalter.
"Ein CSRF-Token ist die einzige saubere Lösung." Anti-CSRF-Tokens bleiben wertvoll für form-basierte Anwendungen, aber SameSite-Cookies decken einen Grossteil der CSRF-Fälle bereits auf der Cookie-Schicht ab. Beide Schichten sind kompatibel; die Kombination ist Defense in Depth.
"X-XSS-Protection schützt uns." Der Header ist historisch; moderne Browser (Chrome, Firefox) haben die zugrundeliegende XSS-Filter-Logik abgeschaltet. CSP ist der aktuelle Schutz.
"HSTS brauchen wir nicht, wir redirecten per 301." Ein 301-Redirect bedeutet, dass der erste Request bereits HTTP-Klartext ist, und genau dort liegt das Angriffsfenster. HSTS schliesst es ab dem zweiten Besuch; preload schliesst es auch für den ersten.
Wie Svelnor hier hilft
Alle Svelnor-Webanwendungen fahren die hier beschriebene Header-Konfiguration als Baseline: strikte nonce-basierte CSP ohne unsafe-inline, SameSite-Lax-Session-Cookies mit Secure und HttpOnly, HSTS mit Preload-Eintrag, vollständige X-Content-Type-Options, Referrer-Policy und Permissions-Policy. Svelnor Upload ist hier besonders relevant: das Widget laeuft als eingebundenes Element in fremden Seiten, die wiederum eigene CSPs mitbringen; unsere Header-Konfiguration sorgt dafür, dass das Widget auch in weich konfigurierten Host-Seiten nicht zum Angriffsvektor wird. Das laufende Content-Security-Policy-Report-Only-Monitoring landet in Svelnor Audit.
Verifikation
- CSP-Evaluator (Google): csp-evaluator.withgoogle.com, prüft eine CSP-Konfiguration auf typische Schwächen.
- Mozilla Observatory: observatory.mozilla.org, aggregierte Einschätzung aller Security-Header einer Seite.
- Hardenize: hardenize.com, ausführliche Analyse inkl. E-Mail- und DNS-Aspekten.
- HSTS-Preload-Eintragung: hstspreload.org.
- MDN-Dokumentation:
Content-Security-Policy,Set-Cookie,Strict-Transport-Security.
Offene Punkte
CSP-Reporting. report-uri oder das modernere report-to liefern Violations an einen Endpoint zur Auswertung. In Produktion werden regelmässig Violations aus Browser-Extensions, Adblockern oder seltenen Browser-Bugs gemeldet, die nicht auf echte Angriffe hindeuten. Das Rauschen muss gefiltert werden, sonst verliert der Report-Stream seinen Nutzen.
Browser-Unterschiede. Einige Direktiven (prefetch-src, report-to) sind nicht in allen Browsern stabil. Wer breit ausliefert, testet in Chromium, Firefox und Safari.
Legacy-Anwendungen. Alte Codebasen mit inline-Event-Handlern (onclick="…") sind mit einer strikten CSP inkompatibel. Die Umstellung auf addEventListener-Style ist Aufwand, zahlt sich aber sowohl für CSP als auch für Code-Qualität aus. Für Zwischenschritte hilft Content-Security-Policy-Report-Only, die geplante Policy ohne Wirkung zu beobachten, bevor sie scharf geschaltet wird.