Security-Header-Architektur für Shopware 6

Alle Security Headers zentral konfigurieren — shopware.yaml für das native CSP-System, Symfony EventSubscriber für weitere Header und die richtige Plugin-Struktur.

Shopware · Schritt für Schritt

Security Headers in Shopware 6 — zwei Konfigurationswege

Shopware 6.5+ basiert auf Symfony und bietet zwei architektonisch verschiedene Wege zur Header-Konfiguration. Die native shopware.yaml steuert die Content Security Policy über csp_templates mit vier Kontexten: default, storefront, administration und store-api. Für alle weiteren Security Headers erstellen Sie einen Symfony EventSubscriber in einem Custom Plugin.

Diese zweigeteilte Architektur ist Shopware-spezifisch: CSP wird nativ verwaltet, weil Shopware den %nonce%-Platzhalter unterstützt und verschiedene Kontexte (Storefront vs. Administration) unterschiedliche Policies benötigen. Alle anderen Header setzen Sie über einen EventSubscriber, der auf kernel.response Events hört.

Implementierung: shopware.yaml und EventSubscriber

Die Konfiguration teilt sich in zwei Bereiche: shopware.yaml für die Content Security Policy (Variante A) und ein EventSubscriber-Plugin für alle weiteren Header (Variante B). Beide Wege funktionieren sowohl in Shopware Cloud als auch Self-Hosted.

Variante A — shopware.yaml (CSP)
config/packages/shopware.yaml Empfohlen
# config/packages/shopware.yaml — CSP-Konfiguration
shopware:
    security:
        csp_templates:
            # Standard für alle Kontexte
            default:
                default-src: "'self'"
                script-src: "'self' '%nonce%' 'strict-dynamic'"
                style-src: "'self' 'unsafe-inline'"
                img-src: "'self' data: https:"
                font-src: "'self'"
                object-src: "'none'"
                base-uri: "'self'"
            # Storefront — mit Payment-Providern
            storefront:
                script-src: "'self' '%nonce%' *.paypal.com js.stripe.com *.klarna.com"
                frame-src: "'self' *.paypal.com *.stripe.com *.klarna.com"
                connect-src: "'self' *.paypal.com *.stripe.com *.klarna.com"
            # Administration — großzügiger
            administration:
                script-src: "'self' 'unsafe-eval' 'unsafe-inline'"
                style-src: "'self' 'unsafe-inline'"
Variante B — EventSubscriber (weitere Header)
SecurityHeaderSubscriber.php Konsolidiert
<?php
// custom/plugins/SecurityHeaders/src/Subscriber/SecurityHeaderSubscriber.php

namespace 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', -256],
        ];
    }

    public function onResponse(ResponseEvent $event): void
    {
        if (!$event->isMainRequest()) {
            return;
        }

        $response = $event->getResponse();

        // HSTS — nur über HTTPS senden
        $response->headers->set(
            'Strict-Transport-Security',
            'max-age=31536000; includeSubDomains; preload'
        );

        // Basis-Header
        $response->headers->set('X-Content-Type-Options', 'nosniff');
        $response->headers->set('Referrer-Policy', 'strict-origin-when-cross-origin');
        $response->headers->set('X-Frame-Options', 'SAMEORIGIN');
        $response->headers->set('Permissions-Policy',
            'camera=(), microphone=(), geolocation=()');

        // Cross-Origin Headers
        $response->headers->set('Cross-Origin-Opener-Policy', 'same-origin');
        $response->headers->set('Cross-Origin-Resource-Policy', 'same-origin');
        $response->headers->set('Origin-Agent-Cluster', '?1');
    }
}
services.xml Registrierung
<!-- custom/plugins/SecurityHeaders/src/Resources/config/services.xml -->
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services">
    <services>
        <service id="SecurityHeaders\Subscriber\SecurityHeaderSubscriber">
            <tag name="kernel.event_subscriber"/>
        </service>
    </services>
</container>
4 CSP-Kontexte in Shopware

Shopware unterscheidet default (Fallback), storefront (Kundenseite), administration (Backend) und store-api (Headless-API). Die Storefront braucht Payment-Provider-Domains, die Administration braucht 'unsafe-eval' für das Vue.js-Backend. Mischen Sie diese Kontexte nicht.

Verifizierung

Nach jeder Konfigurationsänderung muss der Shopware-Cache geleert werden. Ohne bin/console cache:clear werden Änderungen in shopware.yaml und neue EventSubscriber nicht wirksam.

Terminal Verifizierung
# Cache leeren (WICHTIG nach jeder Konfigurationsänderung)
bin/console cache:clear

# Security Headers prüfen
curl -sI https://ihr-shop.de | grep -iE "content-security|strict-transport|x-frame|referrer|x-content-type|permissions-policy"

# Erwartete Ausgabe (alle Header vorhanden):
# content-security-policy: default-src 'self'; ...
# strict-transport-security: max-age=31536000; ...
# x-frame-options: SAMEORIGIN
# referrer-policy: strict-origin-when-cross-origin
# x-content-type-options: nosniff
# permissions-policy: camera=(), microphone=(), ...
Prüfen Sie Storefront und Administration getrennt — die Header können sich aufgrund der verschiedenen CSP-Kontexte unterscheiden. Der Wolf-Agents Web Security Check bewertet 166 Punkte automatisch.

Häufige Fehler

bin/console cache:clear vergessen

Die häufigste Fehlerquelle: Shopware cached Konfigurationen aggressiv. Änderungen in shopware.yaml und neue EventSubscriber werden erst nach bin/console cache:clear wirksam. Im Produktivbetrieb nutzen Sie bin/console cache:warmup nach dem Leeren.

Administration-CSP vs Storefront-CSP verwechselt

Die Administration benötigt 'unsafe-eval' für das Vue.js-Backend. Die Storefront braucht Payment-Provider-Domains. Wenn Sie die Kontexte verwechseln, funktioniert entweder das Admin-Panel oder der Checkout nicht mehr.

Plugin setzt eigene Header die überschrieben werden

Shopware-Plugins können eigene EventSubscriber mit höherer Priorität registrieren. Prüfen Sie die Priorität Ihres Subscribers (negative Werte = späte Ausführung). Mit -256 stellen Sie sicher, dass Ihr Subscriber nach den meisten Plugins läuft.

Shopware Cloud: Kein Server-Config-Zugriff

In Shopware Cloud können Sie weder Nginx noch Apache konfigurieren. Setzen Sie alle Header über shopware.yaml (CSP) und EventSubscriber (Rest). Server-Level-Header wie bei Self-Hosted sind nicht möglich.

Compliance-Relevanz

Eine konsolidierte Security-Header-Architektur in Shopware unterstützt direkt die Anforderungen mehrerer Compliance-Frameworks — besonders relevant für E-Commerce mit Zahlungsverkehr.

PCI DSS 4.0Requirement 6.4.3 — Kontrolle aller auf Zahlungsseiten geladenen Scripts. Seit März 2025 verpflichtend für alle Shops mit Online-Zahlungen.
NIS2Art. 21(e) — Sicherheit bei Erwerb, Entwicklung und Wartung von Netz- und Informationssystemen
BSIAPP.3.1 — Webserver-Absicherung mit Security Headern als Basismaßnahme
DSGVOArt. 32 — Technische Maßnahmen zum Schutz personenbezogener Kundendaten im Shop

Wie steht Ihre Domain bei Implementierungs-Architektur?

Prüfen Sie es jetzt — kostenlos, ohne Registrierung, mit 166 Prüfpunkte.