Security-Header im Überblick: HSTS, X-Frame-Options und mehr
OWASP
0x00
Security · HTTP-Header · Hardening · Magento 2
Security-Header im Überblick
HSTS, X-Frame-Options, CSP frame-ancestors und mehr richtig konfigurieren

Ein gültiges TLS-Zertifikat allein schützt einen Magento-Shop nicht vor Clickjacking, MIME-Sniffing oder stillen Datenlecks über den Referrer-Header. Dieser Artikel zeigt praxisnah, wie HSTS, X-Content-Type-Options, Referrer-Policy, Permissions-Policy und CSP frame-ancestors zusammenspielen, wie sich diese Header korrekt am Webserver oder CDN statt im Anwendungscode setzen lassen und wie Scanner wie securityheaders.com die resultierende Sicherheit bewerten.

12 Min. Lesezeit HSTS · CSP frame-ancestors · Permissions-Policy nginx · Apache · Varnish · Cloudflare

1. Warum HTTP-Security-Header unverzichtbar sind

Ein gültiges TLS-Zertifikat verschlüsselt die Verbindung, sagt dem Browser aber nichts darüber, wie er mit der Antwort umgehen soll. Genau diese Lücke schließen HTTP-Security-Header: Sie weisen den Browser explizit an, unsichere Verbindungen abzulehnen, fremde Inhalte nicht in ein iframe zu laden, Dateitypen nicht zu erraten und sensible Browser-APIs nicht ungefragt freizugeben. Ohne diese Header verlässt sich ein Magento-Shop komplett auf die permissiven Standardeinstellungen der Browser, und die sind für maximale Kompatibilität optimiert, nicht für maximale Sicherheit.

Die Konsequenzen fehlender Header sind konkret messbar: Clickjacking-Angriffe betten eine Checkout-Seite unsichtbar in ein fremdes iframe ein, MIME-Sniffing lässt eine hochgeladene Textdatei als ausführbares Skript interpretieren, und eine zu freizügige Referrer-Policy verrät Warenkorb-Parameter an Drittanbieter-Analytics. Die folgenden Abschnitte behandeln die wichtigsten Security-Header im Detail, von HSTS über nosniff und Referrer-Policy bis zur Konfiguration am Webserver statt im Anwendungscode.

2. Strict-Transport-Security: Syntax, max-age und Preload-Liste

Der Header Strict-Transport-Security (kurz HSTS) weist den Browser an, eine Domain für einen definierten Zeitraum ausschließlich über HTTPS aufzurufen, selbst wenn ein Nutzer explizit http:// eingibt oder einem unverschlüsselten Link folgt. Die Syntax besteht aus drei Teilen: max-age=<Sekunden> legt die Gültigkeitsdauer fest, includeSubDomains weitet den Schutz auf alle Subdomains aus, und preload markiert die Domain für die Aufnahme in die HSTS-Preload-Liste der Browser-Hersteller. Ein produktionstauglicher Wert liegt bei max-age=63072000, also zwei Jahren.

Ohne HSTS bleibt beim ersten Aufruf immer ein kurzes Zeitfenster für SSL-Stripping-Angriffe, weil der Browser die HTTPS-Pflicht erst nach der ersten Antwort kennt. Die Preload-Liste schließt genau diese Lücke, indem HSTS bereits vor dem ersten Kontakt fest im Browser hinterlegt ist. Die Aufnahme erfolgt über hstspreload.org und setzt voraus, dass includeSubDomains und preload auf allen Subdomains inklusive der Root-Domain fehlerfrei gesetzt sind, denn eine Entfernung aus der Liste dauert Monate und betrifft alle gängigen Browser gleichzeitig.


# nginx: HSTS and baseline security headers for a Magento storefront
server {
    listen 443 ssl http2;
    server_name shop.example.com;

    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;

    location / {
        try_files $uri $uri/ /index.php?$args;
    }
}

# Separate HTTP server block: redirect only, never send HSTS over plain HTTP
server {
    listen 80;
    server_name shop.example.com;
    return 301 https://$host$request_uri;
}

3. X-Content-Type-Options: nosniff gegen MIME-Sniffing

Ohne den Header X-Content-Type-Options: nosniff versuchen Browser bei mehrdeutigen oder fehlenden Content-Type-Angaben, den tatsächlichen Dateityp anhand des Inhalts zu erraten, ein Verhalten namens MIME-Sniffing. Lädt ein Nutzer beispielsweise eine Datei mit der Endung .txt hoch, deren Inhalt aber wie HTML oder JavaScript aussieht, kann der Browser sie trotzdem als solches interpretieren und ausführen. In Magento-Shops mit Datei-Uploads, etwa bei Produktbewertungen mit Anhängen oder Kundenservice-Formularen, öffnet das eine reale Angriffsfläche für gespeicherte Cross-Site-Scripting-Angriffe.

Der Header selbst kennt nur einen einzigen gültigen Wert: nosniff. Gesetzt zwingt er den Browser, sich strikt an den deklarierten Content-Type zu halten und keine eigene Erkennung durchzuführen. Für Skripte und Stylesheets bedeutet das zusätzlich, dass sie nur ausgeführt beziehungsweise angewendet werden, wenn der MIME-Type exakt text/javascript beziehungsweise text/css lautet. Da der Header keine Konfigurationsoptionen hat und keine Kompatibilitätsprobleme mit modernen Browsern verursacht, gibt es praktisch keinen Grund, ihn nicht global zu setzen.

4. Referrer-Policy: Datenschutz gegen Analytics-Bedürfnisse

Die Referrer-Policy bestimmt, welche Informationen der Browser beim Verlassen einer Seite im Referer-Header an das Ziel überträgt. Der historische Standardwert no-referrer-when-downgrade sendet die vollständige URL inklusive Query-String an jede beliebige Zielseite, solange keine Herabstufung von HTTPS auf HTTP stattfindet, was in einem Magento-Shop bedeuten kann, dass Suchbegriffe, Gutscheincodes oder interne Session-Parameter an externe Werbenetzwerke durchgereicht werden.

Die empfohlene Balance zwischen Datenschutz und funktionierendem Analytics ist strict-origin-when-cross-origin: Innerhalb der eigenen Domain wird die volle URL übertragen, an fremde Domains dagegen nur der Origin ohne Pfad und Query-String, und bei einer Herabstufung von HTTPS auf HTTP wird gar kein Referrer mehr gesendet. Wer maximale Zurückhaltung braucht, etwa bei sensiblen Checkout-Flows, nutzt no-referrer und verzichtet komplett auf Referrer-Daten, verliert dann aber auch die Zuordnung eingehender Empfehlungslinks im eigenen Analytics-Tool. same-origin ist ein guter Mittelweg für Shops, die überhaupt keine Cross-Origin-Referrer benötigen.

5. Permissions-Policy: Browser-APIs gezielt einschränken

Permissions-Policy hat den älteren, inzwischen umbenannten Feature-Policy-Header abgelöst und steuert, welche mächtigen Browser-APIs eine Seite und ihre eingebetteten iframes nutzen dürfen. Ein typischer Magento-Shop benötigt weder Kamera- noch Mikrofonzugriff und in den meisten Fällen auch keine Geolocation-API, dennoch bleiben diese APIs ohne expliziten Header für jedes eingebundene Skript, einschließlich Drittanbieter-Tracking- oder Zahlungs-iframes, standardmäßig verfügbar.

Die Syntax listet pro Funktion eine sogenannte Allowlist: camera=() deaktiviert die Kamera vollständig für die Seite und alle iframes, geolocation=(self) erlaubt sie nur auf der eigenen Origin, und payment=(self "https://checkout.payment-provider.com") gibt sie gezielt für die eigene Domain und einen benannten Zahlungsanbieter frei. Diese Feinsteuerung reduziert die Angriffsfläche bei kompromittierten Drittanbieter-Skripten erheblich, weil selbst ein eingeschleustes Skript die Kamera nicht aktivieren kann, wenn die Policy es global untersagt. Für die meisten Magento-Installationen ist eine restriktive Grundeinstellung mit gezielten Ausnahmen für tatsächlich genutzte Funktionen wie Zahlungs-Widgets der richtige Ansatz.

6. X-Frame-Options vs. CSP frame-ancestors

X-Frame-Options war über Jahre der Standardschutz gegen Clickjacking und kennt zwei praxisrelevante Werte: DENY verhindert jede Einbettung in ein iframe, unabhängig vom Ursprung, während SAMEORIGIN Einbettung nur von der eigenen Domain erlaubt. Für Checkout-Seiten und den Account-Bereich eines Magento-Shops ist DENY fast immer die richtige Wahl, da es keinen legitimen Grund gibt, diese Seiten fremd einzubetten.

Der Header hat eine strukturelle Schwäche: Er erlaubt nur einen einzigen Ursprung oder gar keinen, eine Liste mehrerer erlaubter Domains ist nicht möglich. Die Content-Security-Policy-Direktive frame-ancestors löst genau das und ist der moderne Ersatz: frame-ancestors 'self' https://partner-portal.example.com erlaubt Einbettung von der eigenen Domain und einem benannten Partner gleichzeitig. Wichtig für die Übergangszeit: frame-ancestors wird von modernen Browsern bevorzugt ausgewertet, wenn beide Header vorhanden sind, während ältere Browser ausschließlich X-Frame-Options verstehen. Beide Header parallel zu setzen ist daher weiterhin sinnvolle Praxis, bis der Legacy-Header vollständig entfallen kann.


# Apache .htaccess: legacy clickjacking protection plus modern CSP replacement
<IfModule mod_headers.c>
    Header always set X-Frame-Options "SAMEORIGIN"
    Header always set Content-Security-Policy "frame-ancestors 'self' https://partner-portal.example.com"

    # Avoid leaking the technology stack alongside the security headers
    Header unset X-Powered-By
</IfModule>

<IfModule mod_headers.c>
    # DENY specifically for checkout and customer account paths
    <If "%{REQUEST_URI} =~ m#^/(checkout|customer)#">
        Header always set X-Frame-Options "DENY"
    </If>
</IfModule>

7. Header-Scans: securityheaders.com und die Bewertung verstehen

Scanner nach dem Vorbild von securityheaders.com senden eine einzelne HTTP-Anfrage an eine URL, werten die zurückgegebenen Response-Header aus und vergeben eine Note von A+ bis F. Die Bewertung basiert auf einer festen Gewichtung: Das Fehlen von Content-Security-Policy und Strict-Transport-Security wirkt sich am stärksten auf die Note aus, während Permissions-Policy und Referrer-Policy geringer gewichtet werden. Eine Note allein sagt aber nichts darüber, ob die einzelnen Werte auch inhaltlich sinnvoll konfiguriert sind, denn ein zu offenes Access-Control-Allow-Origin: * kann trotz guter Gesamtnote ein reales Risiko bleiben.

Wichtiger als die Buchstabennote ist der Blick auf die einzelnen Fundstellen im Detailbericht: Welche Header fehlen komplett, welche sind gesetzt, aber zu freizügig konfiguriert, und welche widersprechen sich zwischen CDN und Origin-Server. Ein Scan sollte nach jedem Deployment automatisiert laufen, etwa als Schritt in der CI-Pipeline mit curl -sI gegen die Staging-URL, damit Regressionen auffallen, bevor ein Kunde den Shop im Produktivbetrieb ungeschützt erreicht.


{
  "url": "https://shop.example.com/",
  "grade": "B",
  "score": 78,
  "headers": {
    "strict-transport-security": {
      "present": true,
      "value": "max-age=63072000; includeSubDomains; preload",
      "weight": "high",
      "status": "pass"
    },
    "content-security-policy": {
      "present": false,
      "weight": "high",
      "status": "fail",
      "note": "Missing CSP allows unrestricted script and frame sources"
    },
    "x-content-type-options": {
      "present": true,
      "value": "nosniff",
      "weight": "medium",
      "status": "pass"
    },
    "referrer-policy": {
      "present": true,
      "value": "strict-origin-when-cross-origin",
      "weight": "low",
      "status": "pass"
    },
    "permissions-policy": {
      "present": false,
      "weight": "low",
      "status": "warn"
    }
  }
}

8. Header am Webserver und CDN konfigurieren statt im Anwendungscode

Security-Header gehören strukturell an die Infrastrukturschicht, nicht in Magento-Controller, Observer oder Layout-XML. Ein setHeader()-Aufruf in PHP läuft erst, nachdem der komplette Magento-Bootstrap durchlaufen wurde, kostet unnötig Rechenzeit und greift überhaupt nicht bei statischen Assets, Fehlerseiten oder Antworten, die direkt aus dem Full Page Cache oder einem CDN-Edge ausgeliefert werden, ohne den Applikationsserver zu erreichen. Header, die am Webserver, in Varnish oder am CDN gesetzt werden, greifen dagegen für jede Antwort, unabhängig davon, welche Schicht sie letztlich ausliefert.

Für Magento-Setups mit Varnish als Full Page Cache empfiehlt sich das Setzen der Header in vcl_deliver, sodass sie sowohl bei Cache-Hits als auch bei Cache-Misses konsistent gesendet werden. Bei einem vorgeschalteten CDN wie Fastly oder Cloudflare lassen sich dieselben Header zusätzlich über Response-Header-Regeln im CDN-Dashboard oder per Edge-Skript setzen, was besonders bei Multi-Origin-Setups mit mehreren Backends hilfreich ist. Entscheidend ist, sich auf eine einzige verantwortliche Schicht festzulegen und nicht redundant an mehreren Stellen dieselben Header zu pflegen.


<?php
// ANTI-PATTERN: setting security headers inside a Magento plugin.
// This code only runs for requests that reach PHP - cached and static
// responses served by Varnish or the CDN never pass through it.
declare(strict_types=1);

namespace Vendor\Module\Plugin;

use Magento\Framework\App\Response\Http;

/**
 * Demonstrates why response headers should not be set in application code.
 */
class SecurityHeaderPlugin
{
    /**
     * Adds headers too late and too narrowly. Webserver/CDN configuration
     * covers every response; this plugin only covers PHP-rendered ones.
     *
     * @param Http $subject
     * @return void
     */
    public function beforeSendResponse(Http $subject): void
    {
        // Never reached for static assets, 404 pages served by Varnish,
        // or CDN edge cache hits - use nginx/Apache/Varnish/CDN instead.
        $subject->setHeader('X-Content-Type-Options', 'nosniff', true);
        $subject->setHeader('X-Frame-Options', 'SAMEORIGIN', true);
    }
}

9. Header-Reihenfolge und Duplikate: CDN gegen Origin

Die folgende Tabelle fasst die wichtigsten Security-Header noch einmal als Checkliste zusammen: Standardzustand ohne Header gegenüber dem empfohlenen Produktivwert und der jeweiligen Schutzwirkung.

Header Fehlender / unsicherer Wert Empfohlener Wert Wirkung
Strict-Transport-Security (kein Header gesetzt) max-age=63072000; includeSubDomains; preload Erzwingt HTTPS, verhindert SSL-Stripping
X-Content-Type-Options (kein Header gesetzt) nosniff Verhindert MIME-Sniffing-Angriffe
X-Frame-Options (kein Header gesetzt) SAMEORIGIN / DENY Clickjacking-Schutz (Legacy)
Content-Security-Policy (kein frame-ancestors) frame-ancestors 'self' Moderner, granularer Clickjacking-Schutz
Referrer-Policy no-referrer-when-downgrade strict-origin-when-cross-origin Reduziert Datenlecks an Drittseiten
Permissions-Policy (kein Header gesetzt) camera=(), microphone=(), geolocation=(self) Deaktiviert ungenutzte Browser-APIs

Sobald ein CDN wie Cloudflare oder Fastly vor dem eigentlichen Webserver sitzt, setzen häufig beide Schichten dieselben Header, meist weil eine Konfiguration migriert wurde, ohne die alte zu entfernen. Das Ergebnis sind doppelte Header in der HTTP-Antwort, etwa zwei X-Frame-Options-Zeilen mit unterschiedlichen Werten. Browser reagieren darauf uneinheitlich: Manche werten nur den ersten Wert aus, manche den letzten, und bei Content-Security-Policy gilt sogar eine Sonderregel, nach der mehrere CSP-Header nicht überschrieben, sondern durch Schnittmenge kombiniert werden, was die Policy unerwartet restriktiv machen kann.

Die zuverlässige Lösung ist eine klare Zuständigkeit: Entweder das CDN setzt sicherheitsrelevante Header und der Origin-Server lässt sie unangetastet, oder umgekehrt, niemals beides gleichzeitig für denselben Header. Mit curl -sI gegen die Live-URL lassen sich doppelte Header schnell aufdecken, da jede Zeile einzeln aufgelistet wird. Bei Varnish zusätzlich beachten: vcl_deliver kann versehentlich einen bereits vom Origin gesetzten Header duplizieren, wenn set resp.http... statt eines vorherigen unset verwendet wird.


#!/usr/bin/env bash
# Detect duplicate security headers between CDN and origin
set -euo pipefail

echo "Checking for duplicate headers on shop.example.com..."
curl -sI "https://shop.example.com/" | grep -i "x-frame-options\|content-security-policy\|strict-transport-security"

# Example output revealing a duplicate (CDN and origin both set it):
# x-frame-options: SAMEORIGIN
# x-frame-options: DENY
# strict-transport-security: max-age=63072000; includeSubDomains; preload

# Fix: unset the header at one layer, keep a single source of truth.
# In Varnish vcl_deliver:
#   unset resp.http.X-Frame-Options;
#   set resp.http.X-Frame-Options = "SAMEORIGIN";

Mironsoft

HTTP-Security-Header, Hardening und Infrastruktur-Konfiguration für Magento-Shops

Security-Header professionell konfigurieren?

Wir analysieren die aktuelle Header-Konfiguration eures Magento-Shops auf Webserver-, Varnish- und CDN-Ebene, schließen Lücken bei HSTS, CSP und Permissions-Policy und beseitigen Duplikate zwischen den Schichten.

Header-Audit

Vollständiger Scan aller Response-Header inklusive CDN- und Origin-Vergleich

Webserver-Hardening

HSTS, nosniff, frame-ancestors und Permissions-Policy in nginx, Apache und Varnish

Monitoring-Setup

Automatisierte Header-Scans in der CI-Pipeline nach jedem Deployment

10. Zusammenfassung

Die wichtigsten Security-Header für Magento-Shops lösen jeweils ein spezifisches Risiko: Strict-Transport-Security erzwingt HTTPS und schließt mit der Preload-Liste die letzte Lücke vor dem allerersten Seitenaufruf. X-Content-Type-Options: nosniff unterbindet MIME-Sniffing-Angriffe über Datei-Uploads. Referrer-Policy und Permissions-Policy reduzieren, welche Daten und Browser-APIs überhaupt für Drittanbieter erreichbar sind. X-Frame-Options und die moderne CSP-Direktive frame-ancestors verhindern Clickjacking, wobei beide Header parallel gesetzt werden sollten, bis ältere Browser vollständig aus dem Traffic verschwunden sind.

Entscheidend für den Erfolg ist die richtige Konfigurationsschicht: Header gehören an den Webserver, nach Varnish oder ans CDN, nicht in Magento-Controller oder Plugins, da nur dort jede Antwort inklusive Cache-Hits und statischer Assets abgedeckt wird. Wer CDN und Origin gleichzeitig konfiguriert, muss auf doppelte Header achten und die Zuständigkeit klar trennen. Ein regelmäßiger Scan mit einem Tool wie securityheaders.com in der CI-Pipeline stellt sicher, dass neue Deployments keine stillen Regressionen bei der Header-Konfiguration einschleusen.

Security-Header im Überblick, das Wichtigste auf einen Blick

HSTS & Preload

max-age=63072000; includeSubDomains; preload erzwingt HTTPS ab dem ersten Aufruf. Anmeldung über hstspreload.org.

nosniff & Referrer-Policy

X-Content-Type-Options: nosniff verhindert MIME-Sniffing. strict-origin-when-cross-origin balanciert Datenschutz und Analytics.

Permissions-Policy & Frame-Schutz

Ungenutzte APIs wie Kamera und Mikrofon deaktivieren. frame-ancestors ersetzt X-Frame-Options mit mehreren erlaubten Domains.

Konfiguration & Testing

Header am Webserver, in Varnish oder am CDN setzen, nie im Magento-Code. Nach jedem Deployment mit einem Scanner prüfen.

11. FAQ: Security-Header im Überblick

1Was sind HTTP-Security-Header und warum reicht TLS allein nicht?
Response-Header, die dem Browser zusätzliche Sicherheitsregeln vorgeben, etwa erzwungenes HTTPS, Clickjacking-Schutz oder eingeschränkte Browser-APIs. TLS verschlüsselt nur die Verbindung, regelt aber nicht den Umgang mit Inhalten, Frames oder APIs.
2Wie funktioniert HSTS und was bedeutet preload?
Erzwingt HTTPS für die Dauer von max-age. preload markiert die Domain zusätzlich für eine feste, im Browser hinterlegte Liste, sodass HTTPS bereits vor dem allerersten Aufruf gilt.
3Wie melde ich eine Domain für die HSTS-Preload-Liste an?
Über hstspreload.org, mit max-age von mindestens einem Jahr und includeSubDomains sowie preload auf allen Subdomains. Ein Rückzug dauert Monate und betrifft alle gängigen Browser.
4Was bewirkt X-Content-Type-Options: nosniff?
Verhindert, dass Browser den Dateityp selbst erraten (MIME-Sniffing), und erzwingt den deklarierten Content-Type. Verhindert unter anderem, dass Uploads versehentlich als Skript ausgeführt werden.
5Welche Referrer-Policy sollte ein Magento-Shop nutzen?
strict-origin-when-cross-origin als bester Kompromiss zwischen Datenschutz und Analytics. Für sensible Checkout-Bereiche ist no-referrer eine sinnvolle Alternative.
6Wofür ist Permissions-Policy gedacht?
Nachfolger von Feature-Policy. Schränkt Browser-APIs wie Kamera, Mikrofon oder Geolocation per Allowlist ein, etwa camera=() zum vollständigen Deaktivieren.
7Ist X-Frame-Options veraltet gegenüber frame-ancestors?
Gilt als Legacy, wird aber weiterhin von älteren Browsern benötigt. frame-ancestors ersetzt es funktional und erlaubt zusätzlich mehrere Domains gleichzeitig.
8Wie interpretiere ich die Note eines Header-Scanners?
CSP und HSTS wiegen am stärksten. Wichtiger als die Note ist der Detailbericht: fehlende Header, zu freizügige Werte und Widersprüche zwischen CDN und Origin.
9Header im Magento-Code oder am Webserver setzen?
Am Webserver, in Varnish oder am CDN, da diese Schicht jede Antwort abdeckt. PHP-Code läuft nur für Anfragen, die tatsächlich bis Magento durchdringen.
10Was passiert bei doppelten Headern von CDN und Origin?
Browser behandeln Duplikate uneinheitlich. Bei CSP werden mehrere Header durch Schnittmenge kombiniert. Eine klar getrennte Zuständigkeit pro Header verhindert das.