HTTP Security Header sind Response-Header, die dem Browser sagen, beim Rendern einer Seite bestimmte Sicherheitsregeln durchzusetzen. Sie werden auf Webserver-Ebene konfiguriert, nicht in WordPress, und kosten beim Aktivieren keine Performance. Eine WordPress-Seite mit korrekten Headern blockiert Clickjacking, Mixed-Content-Downgrades, MIME-Sniffing-Exploits und einen großen Anteil an Cross-Site-Scripting-Payloads. Das Setup ist eine einmalige Änderung in Apaches .htaccess oder in der Nginx-Server-Config. Unten stehen die sieben Header, die 2026 zählen, mit Copy-Paste-Snippets für beide Webserver.
Welche HTTP Security Header sollte eine WordPress-Seite setzen?
Sieben Header decken das realistische Bedrohungsmodell einer Content-Seite ab. Nach Priorität:
Strict-Transport-Security (HSTS). Erzwingt im Browser HTTPS für ein Jahr (oder länger) nach dem ersten Besuch und verhindert HTTPS-Stripping-Angriffe in öffentlichem WLAN. Pflicht, wenn deine Seite eingeloggte Nutzer hat.Content-Security-Policy (CSP). Sagt dem Browser exakt, welche Quellen für JavaScript, CSS, Bilder und Schriften erlaubt sind. Der wirkungsvollste Header gegen XSS, aber auch der heikelste in der Konfiguration, ohne die Seite zu brechen.X-Frame-Optionsoder die CSP-Direktiveframe-ancestors. Verhindert, dass deine Seite in einem iframe auf einer anderen Domain eingebettet wird, und blockiert damit Clickjacking gegen das Login-Formular.X-Content-Type-Options: nosniff. Verhindert, dass Browser den Content-Type einer Antwort raten, was eine Klasse von "Upload eines vermeintlichen Bildes, das eigentlich JavaScript ist"-Angriffen schließt.Referrer-Policy. Steuert, wie viel von der aktuellen URL beim Klick nach außen im Referer-Header gesendet wird. Defaults leaken Query-Strings an Dritte;strict-origin-when-cross-originist die moderne Empfehlung.Permissions-Policy(früher Feature-Policy). Deaktiviert Browser-Features, die deine Seite nicht nutzt (Kamera, Mikrofon, Geolocation), was die Angriffsfläche reduziert, falls ein Drittanbieter-Skript jemals versucht, darauf zuzugreifen.Cross-Origin-Opener-Policy. Isoliert deine Seite von Popups, die sie öffnet, und mildert Spectre-Klasse-Seitenkanal-Angriffe ab. Pflicht, damit SharedArrayBuffer funktioniert.
Was nicht mehr empfohlen wird: X-XSS-Protection (deprecated, Browser ignorieren es), Public-Key-Pins (deprecated, verursachte zu viele Lockouts) und Expect-CT (deprecated seit 2023).
Apache .htaccess: Copy-Paste-Block für Security Header
Den Block ganz oben in die .htaccess im WordPress-Root einfügen, oberhalb des WordPress-Blocks (# BEGIN WordPress). Der IfModule-Guard sorgt dafür, dass das Snippet nicht abstürzt, falls mod_headers fehlt.
<IfModule mod_headers.c>
# HSTS: HTTPS für 1 Jahr erzwingen, Subdomains einschließen, preload-ready
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
# Clickjacking verhindern
Header always set X-Frame-Options "SAMEORIGIN"
# MIME-Sniffing blockieren
Header always set X-Content-Type-Options "nosniff"
# Referrer-Leakage begrenzen
Header always set Referrer-Policy "strict-origin-when-cross-origin"
# Nicht genutzte Browser-Features deaktivieren
Header always set Permissions-Policy "camera=(), microphone=(), geolocation=(), interest-cohort=()"
# Cross-Origin-Isolation
Header always set Cross-Origin-Opener-Policy "same-origin"
# Konservativer Start-CSP; nachträglich verschärfen, wenn klar ist, was die Seite lädt
Header always set Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https:; style-src 'self' 'unsafe-inline' https:; img-src 'self' data: https:; font-src 'self' data: https:; connect-src 'self' https:; frame-ancestors 'self'; base-uri 'self'; form-action 'self';"
</IfModule>Das Schlüsselwort always ist kritisch. Ohne es werden Header nur bei 2xx- und 3xx-Antworten gesendet; mit ihm tragen auch Fehlerseiten und Weiterleitungen die Header. Ohne always sieht ein Angreifer, der einen 500er auslöst, eine ungeschützte Antwort.
Das Modul mod_headers muss aktiv sein. Auf Shared Hosting meistens schon der Fall. Auf selbst verwaltetem Apache: sudo a2enmod headers && sudo systemctl reload apache2.
Nginx: Copy-Paste-Block für Security Header
Den Block in den server { ... }-Block deiner Seite einfügen, typischerweise in /etc/nginx/sites-available/deineseite.conf:
# HSTS: HTTPS für 1 Jahr erzwingen, Subdomains einschließen, preload-ready
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
# Clickjacking verhindern
add_header X-Frame-Options "SAMEORIGIN" always;
# MIME-Sniffing blockieren
add_header X-Content-Type-Options "nosniff" always;
# Referrer-Leakage begrenzen
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# Nicht genutzte Browser-Features deaktivieren
add_header Permissions-Policy "camera=(), microphone=(), geolocation=(), interest-cohort=()" always;
# Cross-Origin-Isolation
add_header Cross-Origin-Opener-Policy "same-origin" always;
# Konservativer Start-CSP; nachträglich verschärfen, wenn klar ist, was die Seite lädt
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https:; style-src 'self' 'unsafe-inline' https:; img-src 'self' data: https:; font-src 'self' data: https:; connect-src 'self' https:; frame-ancestors 'self'; base-uri 'self'; form-action 'self';" always;Das nachgestellte always in Nginx hat denselben Zweck wie in Apache: es sorgt dafür, dass der Header auch bei Fehlerantworten greift. Nach der Änderung Nginx neu laden: sudo nginx -t && sudo systemctl reload nginx.
Die Zwei-Stolperdraht-Regel von Nginx add_header
Nginx hat eine Eigenheit, die immer wieder Leute trifft. Zwei Regeln verinnerlichen, bevor du an Produktiv-Configs gehst:
add_headerersetzt, fügt nicht hinzu. Wenn du Header imserver-Block und nochmal in einemlocation-Block setzt, ersetzen die Location-Block-Header die Server-Block-Header für diese Location. Sie kommen nicht oben drauf. Symptom: Header funktionieren überall, außer in einer bestimmten Location (zum Beispiel in/wp-admin/, wo du eine eigene Regel ergänzt hast).- Immer das
always-Flag ergänzen. Ohne wird eine 404-Seite oder ein 500er ohne deine Security Header ausgeliefert. Angreifer können gezielt Fehler auslösen, um Header-basierte Schutzmaßnahmen zu umgehen.
Apaches Header always set ist das Äquivalent zu Nginx' always-Flag und hat denselben Effekt.
Apache vs Nginx: was ist einfacher zu konfigurieren?
Für Security Header praktisch gleichwertig. Beide nutzen eine einzelne Direktive pro Header und akzeptieren identische Header-Werte. Drei nennenswerte Unterschiede:
- Wo die Config liegt. Apache per
.htaccesskann pro Verzeichnis von jedem mit FTP-Zugriff auf die WordPress-Installation bearbeitet werden. Nginx-Config liegt außerhalb des Document Root und braucht meist SSH plus einen Reload. Für Shared-WordPress-Hosting ist .htaccess praktischer; für Managed-Nginx-Setups ist die Server-Config performanter (Nginx liest .htaccess-Äquivalente nicht bei jedem Request neu, sondern hält die richtige Nginx-Config im Speicher). - Per-Location-Overrides. Apache
.htaccesserbt automatisch die Einstellungen des Parent-Verzeichnisses. Nginxlocation-Blöcke brauchen explizite Neudeklarationen, wenn du einen anpasst (wegen der Merge-Falle oben). - Hosting-Realität. Die meisten Shared-WordPress-Hoster (Hostinger, IONOS, GoDaddy, klassische cPanel-Hoster) laufen auf Apache. Die meisten Managed-WordPress-Hoster (Kinsta, WP Engine, Raidboxes, SiteGround, Cloudways) laufen auf Nginx. Der Marktanteil hat sich in den letzten fünf Jahren von Apache-Mehrheit auf grob 50/50 verschoben.
Sollte ich Security Header lieber in WordPress als auf Webserver-Ebene setzen?
Kannst du, aber Webserver-Ebene ist besser. Drei WordPress-seitige Optionen existieren:
- Security Plugin (Wordfence, iThemes Security usw.). Bietet ein "Security Headers"-Feature, das dieselben Header PHP-seitig ergänzt. Funktioniert, kostet aber ein paar Millisekunden pro Request. Sinnvoll, wenn du keinen Webserver-Zugriff hast.
- Eigener Plugin- oder Theme-Code. Ein kleines MU-Plugin kann mit
header()in PHP jeden Header ausgeben. Gleicher Overhead, gleiche Einschränkungen. - Webserver-Config (empfohlen). Null PHP-Overhead, gilt für jede Antwort inklusive 404-Fehler und statischen Dateien, übersteht WordPress-Crashes.
Das Argument für Webserver-Ebene: PHP-gesetzte Header schützen keine Antworten, die PHP umgehen. Wenn ein Angreifer eine statische Datei direkt erreicht (eine übrig gebliebene .phps-Backup-Datei, ein Upload-Verzeichnis mit HTML-Dateien), greifen PHP-gesetzte Header nicht. Der Webserver sieht jeden Request und ist die richtige Ebene.
Wie tune ich die Content-Security-Policy, ohne meine Seite zu brechen?
CSP ist der wirkungsvollste Security Header und gleichzeitig der, der am ehesten Dinge bricht. Eine WordPress-Seite lädt standardmäßig Skripte und Stylesheets aus dutzenden Quellen: jQuery aus /wp-includes, Theme-Assets, Plugin-Assets, Google Fonts (falls nicht selbst gehostet), Analytics, eingebettete YouTubes etc. Ein strenges CSP, das diese nicht explizit erlaubt, blockiert sie, und die Seite wirkt auf subtile Weise kaputt (Login schlägt fehl, Galerie funktioniert nicht, Analytics stoppt).
Das Zwei-Phasen-Rollout-Muster, das funktioniert:
- Im Report-Only-Modus starten.
Content-Security-Policy-Report-OnlystattContent-Security-Policynutzen. Der Browser blockiert nichts; er protokolliert Verstöße nur in der Entwickler-Konsole. Ein paar Tage über die Seite browsen, beobachten, was geblockt worden wäre, und die legitimen Quellen in der Policy ergänzen. - Auf Enforcing-Modus umschalten. Sobald der Report-Only-Modus bei normalem Browsen null Verstöße zeigt, den Header-Namen zurück auf
Content-Security-Policyändern. Jetzt werden Verstöße geblockt.
Eine häufige Falle: WordPress und viele Plugins nutzen Inline-JavaScript-Event-Handler (onclick="") und Inline-<script>-Blöcke. Ein strenges CSP verlangt entweder 'unsafe-inline' (macht den Großteil des Schutzes zunichte) oder Nonces für jedes Inline-Script (deutliche Code-Anpassungen). Der pragmatische Mittelweg 2026: 'unsafe-inline' erst mal beibehalten, aber die anderen Direktiven festziehen. Zukünftige WordPress-Versionen bewegen sich Richtung nonce-freundlicher Inline-Scripts.
Wie verifiziere ich, dass meine Security Header wirken?
Vier Methoden, vom schnellsten zum autoritativsten:
- InspectWP-Report. Der Security-Abschnitt listet jeden gesetzten Header, seinen Wert und markiert fehlende oder fehlkonfigurierte. Ein Bildschirm.
- curl auf der Kommandozeile.
curl -I https://deineseite.dedruckt die Response-Header. Nach den sieben Headern oben suchen und die Werte verifizieren. - securityheaders.com. Ein kostenloser öffentlicher Scanner, der die Seite benotet (A+ bis F) und erklärt, welche Header fehlen oder schwach gesetzt sind. Industrie-Standard für Header-Audits.
- Browser DevTools. DevTools öffnen (F12), Netzwerk-Tab, den Dokument-Request anklicken, in der Response-Headers-Sektion nachsehen. Praktisch, um CSP-Verstöße live im Console-Tab zu sehen.
Häufige Fehler und Fallen
- HSTS aktivieren, ohne zu prüfen, dass HTTPS überall funktioniert. HSTS zwingt Browser, ein Jahr lang HTTPS zu nutzen. Wenn deine Seite ein kaputtes Zertifikat oder eine Unterseite hat, die nur über HTTP funktioniert, werden Nutzer ausgesperrt. HTTPS gründlich testen, bevor HSTS aktiviert wird. Mit einer kurzen
max-age(etwa 300 Sekunden) starten und auf ein Jahr hochfahren. X-Frame-OptionsUND CSPframe-ancestorssetzen. Beide funktionieren, aberframe-ancestorsist das moderne Äquivalent. Beide gleichzeitig zu setzen ist redundant, aber harmlos; moderne Browser bevorzugenframe-ancestors.includeSubDomainsbei HSTS vergessen. Wenn deine Hauptseite HTTPS ist, eine Subdomain aber noch HTTP ausliefert, können Angreifer über die Subdomain pivoten.includeSubDomainserzwingt HTTPS überall unter deiner Domain. Vor dem Setzen prüfen, dass alle Subdomains HTTPS sprechen.- Ein CSP aus einem generischen Tutorial kopieren. Jede WordPress-Seite lädt andere Drittanbieter-Assets. Ein generisches CSP wird deine Seite brechen. Erst im Report-Only-Modus testen.
- CDN- und Origin-Header vermischen. Wenn Cloudflare davor sitzt, kannst du Header bei Cloudflare (Page Rules oder Transform Rules) oder am Origin setzen. Beide mit unterschiedlichen Werten gleichzeitig zu setzen sorgt beim Debuggen für Verwirrung. Eine Stelle wählen und dokumentieren.
- Reload nach Edit vergessen. Nginx-Änderungen wirken erst nach
systemctl reload nginx. Apache-.htaccess-Änderungen wirken sofort; Änderungen an der Apache-Haupt-Config brauchen einen Reload.
Was ist mit HTTP/3 und der modernen Header-Story?
HTTP/3 ändert nichts daran, welche Header gesetzt werden sollten; die Header-Semantik ist über HTTP/1.1, HTTP/2 und HTTP/3 identisch. Ein Header, der unter HTTP/3 relevant wird, ist Alt-Svc, der Clients, die über HTTP/2 angekommen sind, die HTTP/3-Verfügbarkeit signalisiert. Die meisten Webserver setzen ihn automatisch.
Die Browser-Landschaft bewegt sich auch zunehmend dahin, moderne Defaults durchzusetzen, selbst wenn Header fehlen. Chrome und Firefox nutzen mittlerweile strict-origin-when-cross-origin als Default für Referrer-Policy, falls kein Header gesendet wird, und nehmen bei jeder Seite, die jemals über HTTPS ausgeliefert wurde, zunehmend HTTPS an. Die Header trotzdem explizit zu setzen ist weiterhin empfehlenswert, weil die Defaults je nach Browser-Version variieren und weil Nicht-Browser-HTTP-Clients (curl, Skripte, Monitoring-Tools) diese Defaults nicht umsetzen.
Was InspectWP prüft
Der Security-Abschnitt jedes InspectWP-Reports inspiziert die Response-Header deines Hauptdokuments und meldet, welche der Standard-Security-Header vorhanden sind, welche Werte sie haben und welche fehlen oder auf nicht empfohlene Werte gesetzt sind. Fehlendes HSTS auf einer HTTPS-Seite wird als Warnung geflaggt; fehlendes X-Content-Type-Options als Hinweis; ein CSP, das auf default-src * gesetzt ist (effektiv gar keine Policy), wird als Fehlkonfiguration markiert. Der Report vermerkt auch, wenn Header auf CDN-Ebene statt auf Origin-Ebene gesetzt sind, weil das beeinflusst, was du anpassen müsstest, um sie zu ändern. Empfohlener Zustand: alle sieben Header vorhanden mit sinnvollen Werten, und CSP entweder im Report-Only-Modus während du es tunest oder im Enforcing-Modus, sobald getuned.