Server-Rezept
Zwanzig Zeilen in einem Plugin decken jede Seite Ihrer Storefront ab. Sorgfalt braucht die Kasse, wo eine strenge Richtlinie genau den Zahlungsanbieter blockiert, mit dem Ihr Kunde gerade bezahlen will.
01 Wohin es gehört
Shopware 6 ist eine Symfony-Anwendung, das Kernel-Response-Event ist also die richtige Stelle: es feuert bei jeder Antwort der Storefront, bevor irgendetwas den Browser erreicht. Ein kleines Plugin mit einem einzigen Subscriber hält die Konfiguration aus Ihrem Theme heraus und lässt sich mit einem Klick abschalten, wenn ein Header etwas kaputt macht.
Die Pfadsperre zählt. Die Administration ist eine JavaScript-Anwendung, die auf Inline-Skripte und Blob-Worker angewiesen ist, und eine für die Storefront geschriebene Richtlinie verhindert, dass sie überhaupt lädt; die API bedienen Maschinen, die keinen dieser Header brauchen. Nimmt man den Admin- und den API-Pfad aus, kostet ein Fehler in der Richtlinie eine kaputte Storefront-Seite und nicht einen Shop, den Sie nicht mehr verwalten können.
02 Das Rezept
Ein sicherer Ausgangspunkt für eine Storefront. Der frame-src-Eintrag ist der shopspezifische: PayPal, Klarna und die meisten anderen Anbieter rendern ihren Zahlungsschritt in einem iframe auf Ihrer Seite, und eine auf den eigenen Ursprung begrenzte Richtlinie verbietet genau das.
<?php declare(strict_types=1); namespace Swag\SecurityHeaders\Subscriber; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpKernel\Event\ResponseEvent; use Symfony\Component\HttpKernel\KernelEvents; class SecurityHeaderSubscriber implements EventSubscriberInterface { public static function getSubscribedEvents(): array { return [KernelEvents::RESPONSE => 'onResponse']; } public function onResponse(ResponseEvent $event): void { $path = $event->getRequest()->getPathInfo(); if (str_starts_with($path, '/admin') || str_starts_with($path, '/api')) { return; } $event->getResponse()->headers->add([ 'Strict-Transport-Security' => 'max-age=63072000; includeSubDomains',
'Content-Security-Policy' => "default-src 'self'; frame-src 'self' https://www.paypal.com; object-src 'none'; base-uri 'self'; form-action 'self' https://www.paypal.com; frame-ancestors 'self'",
'X-Frame-Options' => 'SAMEORIGIN',
'X-Content-Type-Options' => 'nosniff',
'Referrer-Policy' => 'strict-origin-when-cross-origin',
'Permissions-Policy' => 'geolocation=(), camera=(), microphone=(), payment=(self "https://www.paypal.com"), usb=()', ]); } } Zwei Anpassungen, bevor das Ihres ist. Ersetzen Sie den PayPal-Host durch das, was Ihre eigenen Zahlungs-, Tracking- und Consent-Werkzeuge tatsächlich laden, und holen Sie sich diese Liste aus Content-Security-Policy-Report-Only statt aus dem Gedächtnis. Und prüfen Sie gegen eine echte Bestellung: eine Richtlinie, die auf der Produktseite durchgeht, kann den letzten Schritt der Kasse trotzdem anhalten.
03 Zeile für Zeile
Jeder Eintrag aus dem Block oben einzeln, damit Sie weglassen können, was nicht zu Ihrem Shop passt, statt etwas einzufügen, das Sie nicht erklären können.
Strict-Transport-Security Was er macht. Legt Browser darauf fest, Ihren Shop zwei Jahre lang nur über HTTPS zu erreichen. Setzen Sie ihn am Webserver, wenn Sie können, dann gilt er auch für Mediendateien, die ohne PHP ausgeliefert werden, und fügen Sie ihn erst hinzu, wenn HTTPS auf jeder genutzten Subdomain funktioniert.
'Strict-Transport-Security' => 'max-age=63072000; includeSubDomains', Content-Security-Policy Was er macht. Fangen Sie hiermit an und nicht mit der erzwingenden Fassung. Im Shop blockiert die erzwingende Variante Zahlungs-iframes, Tracking-Pixel und Consent-Banner, und Sie erfahren das in dem Moment, in dem ein Kunde bezahlen wollte. Report-Only sammelt dieselbe Liste, ohne Sie die Bestellung zu kosten.
'Content-Security-Policy' => "default-src 'self'; frame-src 'self' https://www.paypal.com; object-src 'none'; base-uri 'self'; form-action 'self' https://www.paypal.com; frame-ancestors 'self'",
'Content-Security-Policy-Report-Only' => "default-src 'self'; frame-src 'self' https://www.paypal.com; object-src 'none'; base-uri 'self'; form-action 'self' https://www.paypal.com; frame-ancestors 'self'; report-uri /csp-report", X-Frame-Options Was er macht. SAMEORIGIN statt DENY, weil Teile von Shopware eigene Seiten einbetten. Dieser Header regelt, ob Ihr Shop anderswo eingebettet wird; mit den Zahlungs-iframes, die Sie selbst einbetten, hat er nichts zu tun, dafür ist frame-src zuständig.
'X-Frame-Options' => 'SAMEORIGIN', X-Content-Type-Options Was er macht. Sagt dem Browser, Ihren angegebenen Inhaltstypen zu vertrauen, statt zu raten. Überall sicher, und in einem Shop, der Lieferantenmedien annimmt, nimmt er eine ganze Angriffsklasse aus dem Spiel.
'X-Content-Type-Options' => 'nosniff', Referrer-Policy Was er macht. Sendet die vollständige Adresse innerhalb Ihres eigenen Shops und nach außen nur die bloße Domain. Das lohnt sich: eine vollständige Adresse verrät jedem eingebundenen Dritten das Produkt, den Suchbegriff und manchmal die Bestellnummer.
'Referrer-Policy' => 'strict-origin-when-cross-origin', Permissions-Policy Was er macht. Schaltet Kamera, Mikrofon, Standort und USB-Zugriff für Ihre Seiten und alles Eingebettete ab und lässt die Bezahlfunktion allein Ihren eigenen Seiten und Ihrem Zahlungsanbieter. Lassen Sie Standort aus, solange keine Händlersuche ihn braucht, und denken Sie daran: was Sie erlauben, darf der Zahlungsanbieter in Ihrem iframe auch.
'Permissions-Policy' => 'geolocation=(), camera=(), microphone=(), payment=(self "https://www.paypal.com"), usb=()', 04 Nachprüfen
Shopware cacht Storefront-Antworten, und davor sitzt meist noch ein Reverse Proxy wie Varnish oder Fastly. Eine gecachte Antwort ist entstanden, bevor es Ihren Subscriber gab, ein aktiviertes Plugin belegt also für sich genommen nichts.
bin/console cache:clear curl -sI https://example.com | grep -i "^strict-transport\|^content-security\|^x-frame" curl -sI https://example.com/checkout/cart | grep -i "^content-security" Prüfen Sie Warenkorb und Kasse und nicht nur die Startseite. Das sind die Seiten, die Dritte einbetten, und dort hört eine Richtlinie auf zu funktionieren, die überall sonst gut aussah.
05 Fragen
Sollten Sie, wenn der Server Ihnen gehört: dort sind auch Mediendateien und Fehlerseiten abgedeckt, die PHP nie erreichen. Der Subscriber ist für Hosting, bei dem Sie die Serverkonfiguration nicht bearbeiten können, und für den Fall, dass Storefront und Administration auf derselben Domain verschiedene Richtlinien brauchen.
Mit großer Wahrscheinlichkeit frame-src, das auf Ihren default-src-Wert zurückfällt. Der Anbieter rendert seinen Schritt in einem iframe von seiner eigenen Domain, und eine Richtlinie, die nur Ihren Ursprung erlaubt, blockiert ihn. Nehmen Sie den Host des Anbieters in frame-src auf und prüfen Sie zusätzlich connect-src, falls sein Widget nach Hause telefoniert.
Der Subscriber läuft bei jeder Antwort, auch bei einer aus dem Shopware-HTTP-Cache, die Header werden also in beiden Fällen gesetzt. Veralten kann eine Seite, die ein Proxy vor Shopware hält, denn der legt Header zusammen mit dem Inhalt ab. Leeren Sie diese Ebene mit.
Ja, und mehrere machen das sauber, samt Einstellungsmaske. Was Sie kaufen, ist Bequemlichkeit und nicht bessere Header: die Werte sind dieselben, und Sie handeln sich ein weiteres Plugin ein, das über Shopware-Updates hinweg kompatibel bleiben muss.
06 Im Detail
Diese Seite ist die Konfiguration. Diese Ratgeber erklären, was jeder Header wirklich macht und wie Sie seinen Wert wählen.
Was jeder Response-Header bewirkt, welche Ihre Website senden sollte und wie Sie sie richtig konfigurieren.
Der stärkste Schutz gegen Cross-Site-Scripting: welche Direktiven Sie setzen, wie Sie eine Richtlinie im Report-Only-Modus einführen und wie Sie erzwingend werden, ohne Ihre Website zu zerlegen.
Strict-Transport-Security erklärt: was max-age, includeSubDomains und preload wirklich bewirken und warum die Preload-Liste eine Entscheidung ist, die Sie nicht schnell zurücknehmen können.
Secure, HttpOnly und SameSite: die Cookie-Attribute, die eine Sitzung vor Skripten und fremden Seiten schützen, samt Einstellungen für einen typischen Stack.
Wie eine unsichtbare Überlagerung aus einem Besucherklick eine Aktion auf Ihrer Website macht, und die zwei Header, die das verhindern: X-Frame-Options für ältere Clients, frame-ancestors für alles andere.
Welcher Teil Ihrer URLs an fremde Seiten geht, wenn ein Besucher weiterklickt: die fünf Werte, die zählen, was jeder davon preisgibt und welcher der sinnvolle Standard ist.
Kamera, Mikrofon, Standort und Bezahlfunktion für Ihre Website und alle eingebetteten Inhalte abschalten: die Syntax der Positivliste und warum eine nicht genannte Funktion keine abgeschaltete Funktion ist.
Die Einträge, die verhindern, dass jemand in Ihrem Namen Mails verschickt, und der, der Ihre DNS-Antworten ehrlich hält: was jeder leistet und in welcher Reihenfolge Sie sie einführen.
Die Datei, die Sicherheitsforschern sagt, wohin eine Schwachstelle gemeldet wird. Zwei Pflichtfelder, zehn Minuten Arbeit, und der Unterschied zwischen einer privaten und einer öffentlichen Meldung.
Ein Header, der heute stimmt, kann nach dem nächsten Deploy fehlen. Drei Wege, das zu bemerken: ein Cronjob mit curl, eine Prüfung in Ihrer CI-Pipeline und ein geplanter Scan, jeweils mit dem, was er findet und was nicht.
Wie sich eine Richtlinie durch Deploys, Plugins und CDN-Regeln unbemerkt ändert und wie Sie es merken: ein Header-Diff, Verstoßmeldungen über report-to und was ein Scan-Vergleich zeigen kann und was nicht.
Weiterlesen
Jeder Ratgeber steht für sich, zusammen decken sie ab, worauf unser Scanner schaut. Wählen Sie den, der Ihrer nächsten Frage am nächsten kommt.
Unser kostenloser Quickscan liest die Header aus Ihrer ausgelieferten Antwort und nicht aus Ihrer Plugin-Liste, und erklärt jeden Befund verständlich.