Wie CSP, HSTS und X-Frame-Options als feste Testassertion in die bestehende E2E-Suite wandern, damit eine stille Regression sofort auffällt
Ein HTTP-Security-Header wie die Content-Security-Policy oder der X-Frame-Options-Header wird meist einmalig, oft im Rahmen eines Security-Audits, sorgfältig konfiguriert und danach kaum noch angefasst. Genau diese Ruhe wird zur Falle, sobald ein späteres Refactoring des Webservers, ein neues CDN oder eine geänderte Nginx-Konfiguration den Header versehentlich verkürzt, entfernt oder falsch setzt, denn im normalen Betrieb eines Onlineshops merkt niemand sofort, dass ein Schutzmechanismus lautlos verschwunden ist. Wird die Prüfung der wichtigsten Security-Header stattdessen als feste Assertion in die ohnehin vorhandene End-to-End-Testsuite aufgenommen, fällt eine solche Regression bereits beim nächsten Testlauf auf, lange bevor sie in Produktion zu einem echten Sicherheitsproblem wird.
Inhaltsverzeichnis
- 1. Warum Security-Header ohne Test lautlos verschwinden
- 2. Welche Header eine feste Testassertion verdienen
- 3. Praktisches Beispiel mit Cypress
- 4. Dasselbe Vorgehen mit Playwright
- 5. Umgang mit CSP im Report-Only-Modus
- 6. Unterschiedliche Header je Seitentyp berücksichtigen
- 7. Integration in die CI-Pipeline
- 8. Häufige Fallstricke bei Header-Tests
- 9. Security-Header-Tests im Überblick
- 10. Zusammenfassung
- 11. FAQ
1. Warum Security-Header ohne Test lautlos verschwinden
HTTP-Security-Header werden in der Praxis meist an einer Stelle konfiguriert, die weit entfernt vom eigentlichen Anwendungscode liegt, etwa in der Nginx-Konfiguration, im Reverse Proxy, in einem CDN oder in einer Middleware, die separat vom Magento-Kern gepflegt wird. Diese räumliche Trennung zwischen Header-Konfiguration und Anwendungslogik führt dazu, dass ein Header bei einem Infrastruktur-Umbau, einem CDN-Wechsel oder einer schlicht vergessenen Konfigurationszeile verschwinden kann, ohne dass irgendein funktionaler Test der Anwendung dies bemerkt, denn die Seite selbst funktioniert für Käuferinnen und Käufer optisch und funktional weiterhin einwandfrei.
Ohne eine automatisierte Prüfung bleibt die einzige Absicherung ein manueller, meist nur bei Audits durchgeführter Blick in die Antwort-Header, was in der Praxis bedeutet, dass zwischen zwei solchen manuellen Prüfungen Monate vergehen können, in denen ein fehlender Header unentdeckt bleibt. Ein automatisierter Test, der bei jedem Deployment oder zumindest täglich in der CI-Pipeline läuft, schließt genau diese Lücke, indem er die Header-Präsenz und den Header-Inhalt bei jeder Ausführung neu und zuverlässig überprüft, unabhängig davon, ob sich jemand im Team aktiv daran erinnert.
Besonders kritisch ist dieses Risiko für einen Onlineshop, da Kundendaten, Zahlungsinformationen und Sessions direkt vom Schutzniveau dieser Header abhängen: Eine fehlende oder zu lax konfigurierte Content-Security-Policy öffnet etwa Cross-Site-Scripting-Angriffen Tür und Tor, während ein fehlender HSTS-Header einen Downgrade auf unverschlüsseltes HTTP erleichtert, zwei Szenarien, die sich beide durch einen einfachen, wiederholbaren Test zuverlässig ausschliessen lassen.
2. Welche Header eine feste Testassertion verdienen
Nicht jeder theoretisch mögliche Security-Header muss in jedem Testlauf einzeln geprüft werden, aber eine kleine Kerngruppe hat sich in der Praxis als besonders prüfungswürdig etabliert: die Content-Security-Policy (CSP) als zentrale Verteidigung gegen Cross-Site-Scripting, der Strict-Transport-Security-Header (HSTS) gegen Protokoll-Downgrades, X-Frame-Options beziehungsweise die entsprechende CSP-Direktive frame-ancestors gegen Clickjacking, sowie X-Content-Type-Options gegen MIME-Sniffing-Angriffe.
Für jeden dieser Header lohnt sich nicht nur die reine Präsenzprüfung, sondern auch eine inhaltliche Prüfung der konkreten Direktiven, denn ein vorhandener, aber inhaltlich zu lax konfigurierter Header bietet kaum mehr Schutz als ein fehlender Header. Eine CSP mit der Direktive script-src * etwa erfüllt zwar formal die Anforderung, einen CSP-Header zu setzen, verhindert aber praktisch keinen einzigen Cross-Site-Scripting-Angriff, weshalb der Test die tatsächliche Direktive und nicht nur das blosse Vorhandensein des Headers prüfen sollte.
3. Praktisches Beispiel mit Cypress
In Cypress lässt sich der Zugriff auf die tatsächlichen Response-Header über cy.request() realisieren, da ein regulärer cy.visit()-Aufruf die Header nicht direkt zurückgibt, sondern lediglich die gerenderte Seite lädt. Der folgende Test prüft für die Magento-Checkout-Seite exemplarisch mehrere Header in einer gemeinsamen, klar strukturierten Testfunktion.
describe('Security-Header auf der Checkout-Seite', () => {
it('setzt CSP, HSTS und X-Frame-Options korrekt', () => {
cy.request('/checkout').then((response) => {
const headers = response.headers;
expect(headers).to.have.property('content-security-policy');
expect(headers['content-security-policy']).to.include("default-src 'self'");
expect(headers['content-security-policy']).to.not.include('script-src *');
expect(headers).to.have.property('strict-transport-security');
expect(headers['strict-transport-security']).to.include('max-age=');
expect(headers['strict-transport-security']).to.include('includeSubDomains');
expect(headers).to.have.property('x-frame-options');
expect(headers['x-frame-options']).to.eq('SAMEORIGIN');
expect(headers).to.have.property('x-content-type-options');
expect(headers['x-content-type-options']).to.eq('nosniff');
});
});
});
4. Dasselbe Vorgehen mit Playwright
Playwright erlaubt den Zugriff auf Response-Header sowohl über page.goto(), das ein Response-Objekt zurückgibt, als auch über die eigenständige Request-API, ohne dass dafür ein vollständiges Browser-Rendering nötig wäre, was den Test spürbar beschleunigt, wenn ausschliesslich Header und keine sichtbaren Inhalte geprüft werden sollen.
import { test, expect } from '@playwright/test';
test('Startseite liefert erwartete Security-Header', async ({ request }) => {
const response = await request.get('/');
const headers = response.headers();
expect(headers['content-security-policy']).toContain("object-src 'none'");
expect(headers['x-frame-options'] ?? headers['content-security-policy']).toBeTruthy();
expect(headers['referrer-policy']).toBe('strict-origin-when-cross-origin');
expect(response.status()).toBe(200);
});
5. Umgang mit CSP im Report-Only-Modus
Viele Teams führen eine neue oder verschärfte Content-Security-Policy zunächst im Report-Only-Modus über den Header Content-Security-Policy-Report-Only ein, bei dem Verstösse zwar protokolliert, aber nicht tatsächlich blockiert werden, um vor der endgültigen Aktivierung ungewollte Nebenwirkungen im echten Betrieb sicher beobachten zu können, ohne dabei bereits Funktionalität für echte Käuferinnen und Käufer zu gefährden.
Ein Testfall für diese Übergangsphase sollte klar zwischen beiden Headernamen unterscheiden und je nach aktuellem Projektstatus explizit prüfen, welcher der beiden gesetzt ist, damit später beim geplanten Umschalten von Report-Only auf den tatsächlich erzwingenden Header bewusst auch der zugehörige Test angepasst wird, statt dass die Testsuite unbemerkt weiterhin nur den laxeren Report-Only-Header validiert, obwohl der Header in der Zwischenzeit auf den strengeren, erzwingenden Modus umgestellt wurde.
6. Unterschiedliche Header je Seitentyp berücksichtigen
In einem Magento-Shop unterscheiden sich die tatsächlich notwendigen Header teils je nach Seitentyp: Eine eingebettete PayPal- oder Klarna-Zahlungsseite benötigt unter Umständen gezielt gelockerte frame-src- oder connect-src-Direktiven in der CSP, während die übrige Shopseite deutlich restriktiver konfiguriert sein sollte, weshalb ein einzelner, pauschaler Header-Test für die gesamte Domain die tatsächliche Realität oft nicht korrekt abbildet.
Sinnvoller ist deshalb ein kleines Set gezielter Testfälle je relevantem Seitentyp, etwa je ein eigener Test für Kategorieseite, Produktseite, Warenkorb, Checkout und Kundenkonto, wobei jeder Testfall die für genau diesen Seitentyp erwarteten, spezifischen Header-Direktiven prüft, statt eine einzige, generische Erwartung auf die gesamte Shop-Domain zu projizieren, die den unterschiedlichen tatsächlichen Anforderungen der einzelnen Seitentypen nicht gerecht wird.
Ein weiterer, in der Praxis leicht übersehener Sonderfall betrifft eingebettete Hilfe- oder Support-Widgets von Drittanbietern, die auf vielen Kundenkonto-Seiten eingebunden sind und ebenfalls eigene, oft grosszügigere Direktiven in der Content-Security-Policy benötigen, weshalb sich ein isolierter Testfall gerade für diese Seite lohnt, um sicherzustellen, dass die dort notwendigen Lockerungen nicht versehentlich auf andere, deutlich sensiblere Seitentypen wie den Checkout übergreifen, was ein wichtiger, aber oft erst spät im Projektverlauf entdeckter Qualitätsaspekt ist.
7. Integration in die CI-Pipeline
Damit ein fehlender Header tatsächlich frühzeitig auffällt, sollten die Header-Tests nicht nur lokal, sondern als fester Bestandteil der CI-Pipeline bei jedem Pull Request und zusätzlich regelmässig gegen die Produktivumgebung ausgeführt werden, da eine falsch konfigurierte Infrastrukturänderung (etwa am CDN oder Load Balancer) unter Umständen außerhalb des eigentlichen Deployments der Anwendung passiert und dadurch von reinen Pre-Deployment-Tests gar nicht erfasst würde.
Ein separater, täglich laufender Smoke-Test gegen die echte Produktivdomain, unabhängig vom regulären Deployment-Zyklus, schließt diese Lücke zuverlässig, indem er auch Header-Änderungen erkennt, die durch Infrastruktur-Teams außerhalb des eigentlichen Anwendungscodes vorgenommen wurden, etwa im Rahmen einer CDN-Konfigurationsänderung, die vom Entwicklungsteam möglicherweise gar nicht direkt bemerkt wird.
8. Häufige Fallstricke bei Header-Tests
Ein verbreiteter Fehler ist, den Header-Test ausschliesslich gegen die Startseite laufen zu lassen und daraus fälschlich zu schließen, alle übrigen Seiten seien ebenso abgesichert, obwohl unterschiedliche Seitentypen, wie im vorherigen Abschnitt beschrieben, durchaus unterschiedliche Header-Konfigurationen besitzen können, etwa weil eine eingebettete Drittanbieter-Zahlungsseite eine abweichende CSP benötigt.
Ein weiterer häufiger Fallstrick ist eine zu strikte, auf exakte Zeichenkettengleichheit prüfende Assertion für die CSP, obwohl sich die Reihenfolge der einzelnen CSP-Direktiven oder unkritische Zusatzwerte gelegentlich ändern können, ohne dass die eigentliche Schutzwirkung dadurch beeinträchtigt wird. Ein robusterer Test prüft deshalb gezielt, ob bestimmte, sicherheitsrelevante Direktiven enthalten sind, statt die gesamte Zeichenkette exakt und zeichengenau zu vergleichen, was den Test unnötig zerbrechlich gegenüber harmlosen, funktional irrelevanten Änderungen machen würde.
9. Security-Header-Tests im Überblick
Die folgende Tabelle fasst die wichtigsten Header und die jeweils passende Testtiefe zusammen.
| Header | Schutzziel | Empfohlene Testtiefe |
|---|---|---|
| Content-Security-Policy | Cross-Site-Scripting, Dateninjektion | Inhaltliche Direktivenprüfung, kein exakter Stringvergleich |
| Strict-Transport-Security | Protokoll-Downgrade auf HTTP | Präsenz plus max-age-Mindestwert prüfen |
| X-Frame-Options / frame-ancestors | Clickjacking | Erwarteten Wert pro Seitentyp prüfen |
| X-Content-Type-Options | MIME-Sniffing | Reine Präsenz- und Wertprüfung genügt |
| Referrer-Policy | Ungewollter Datenabfluss über Referrer | Erwarteten Policy-Wert prüfen |
Mironsoft
E2E-Teststrategie, CI-Integration und stabile Testsuiten
Testsuiten, die Bugs finden statt nur rot zu blinken?
Wir prüfen bestehende E2E-Testsuiten auf Flakiness, fehlende Testisolation und ineffiziente CI-Laufzeiten und bauen daraus eine Teststrategie, die tatsächlich Vertrauen schafft statt nur Haken zu setzen.
Test-Audit
Flaky Tests, Testpyramide und Coverage-Lücken systematisch aufdecken.
CI-Optimierung
Parallele Ausführung, Retry-Strategien und schnelle Feedback-Zyklen aufbauen.
Cypress/Playwright-Setup
Robuste E2E-Suiten für Magento-Frontends von Grund auf einrichten.
10. Zusammenfassung
Security-Header-Tests: Das Wichtigste auf einen Blick
Kernidee
Security-Header als feste Assertion in die bestehende E2E-Suite aufnehmen statt nur manuell bei Audits zu prüfen.
Testtiefe
Konkrete Direktiven prüfen, nicht nur die blosse Präsenz eines Headers.
Seitentyp-Bezug
Unterschiedliche Seitentypen wie Checkout oder eingebettete Zahlungsseiten benötigen eigene Testfälle.
CI-Anbindung
Tests bei jedem Pull Request und zusätzlich täglich gegen Produktion ausführen.