HTTP-Sicherheits-Header für WordPress: Mein A-Setup 2026 (mit .htaccess)
- Was bringt welcher Header?
- Der aktuelle Stand von seotologie.de
- Mehrschichtige Sicherheits-Architektur
- CSP: So restriktiv wie möglich – ohne Funktionsverlust
- Technische Voraussetzungen & Risiken
- Mein Header-Setup für die .htaccess (Stand 2026)
- FAQ: Die häufigsten Fragen
- Troubleshooting: Was tun, wenn etwas nicht funktioniert?
- Mein Fazit
Ich zeige dir hier das Setup, mit dem ich meine Seite absichere – inklusive der Lösung für das größte Problem: Ein geschütztes System bei gleichzeitig voll funktionsfähigem WordPress-Frontend und -Backend.
Was bringt welcher Header?
| Header | Nutzen in der Praxis |
|---|---|
| HSTS | Erzwingt HTTPS und verhindert Man-in-the-Middle-Angriffe. |
| ContentContentContent ist jede Information, die du auf einer Website bereitstellst, um Nutzer anzusprechen. Das können geschriebene Inhalte wie Blogartikel, aber auch Bilder, Videos oder Infografiken…Mehr lesen-Security-Policy | Legt fest, woher Skripte, Styles, Bilder und Schriften geladen werden dürfen – der wichtigste Schutz gegen XSS. |
| X-Frame-Options | Clickjacking-Schutz: Verhindert das Einbetten in fremde Seiten. |
| X-Content-Type-Options | Stoppt MIME-Sniffing (Schutz vor Schadcode in Uploads). |
| Referrer-Policy | Schützt die Privatsphäre deiner Nutzer beim Verlassen der Seite. |
| Permissions-Policy | Schaltet Browser-Funktionen ab, die die Seite nicht braucht – Kamera, Mikrofon, Standort, Zahlungen. |
| COOP / CORP / COEP | Trennt deine Seite von fremden Fenstern (COOP) und verhindert, dass fremde Websites deine Dateien einbinden (CORP). COEP bleibt bewusst offen – siehe FAQ. |
Die ersten sechs Zeilen sind genau die Header, die securityheaders.com für die Note bewertet.
Der aktuelle Stand von seotologie.de
Bei securityheaders.com erreicht seotologie.de die Note A – alle sechs bewerteten Header sind aktiv (Messung vom 24.09.2026). Warum es trotzdem kein A+ ist, erkläre ich weiter unten ganz offen.
Mehrschichtige Sicherheits-Architektur
HTTP-Header sind eine starke erste Verteidigungslinie – aber sie decken nur den Browser-Bereich ab. Für einen vollständigen Schutz braucht es zusätzliche Sicherheitsschichten auf Server- und Anwendungsebene. Auf seotologie.de nutze ich deshalb drei ergänzende Komponenten:
1. Web Application Firewall (WAF)
Blockiert typische Angriffe wie Brute-Force und SQL-Injection, noch bevor WordPress überhaupt geladen wird.
2. Kontrolle ausgehender Verbindungen
WordPress darf nur mit ausgewählten, vertrauenswürdigen Diensten Kontakt aufnehmen. Unerwartete Verbindungen nach außen werden blockiert – das erschwert Datenabflüsse über kompromittierte Plugins.
3. Eigene Bot- und Angriffserkennung
Erkennt automatisierte Scans und typische Angriffsmuster und sperrt auffällige Zugriffe automatisch.
CSP: So restriktiv wie möglich – ohne Funktionsverlust
Die Content-Security-Policy (CSP) ist das Herzstück der Absicherung – aber auch die größte Herausforderung. Eine einzige CSP für die ganze Website ist immer ein Kompromiss: Das Backend braucht mehr Freiheiten als das öffentliche Frontend. Deshalb nutze ich drei Stufen:
| Bereich | Was die CSP dort erlaubt |
|---|---|
| Frontend (alle öffentlichen Seiten) | Die strengste Stufe: default-src 'self' –
Skripte, Styles, Schriften und Bilder
ausschließlich von der eigenen Domain. Keine iFrames (frame-src 'none'), dazu
base-uri, form-action und frame-ancestors auf
'self'. Einzige Ausnahme nach außen: der Statistik-Endpunkt des
Cookie-Consent. |
Backend (/wp-admin,
/wp-login) |
Wie das Frontend, zusätzlich die Cloud-Endpunkte des Cookie-Consent-Plugins, die nur die Verwaltung braucht. |
Customizer (/wp-admin/customize.php)
|
Zusätzlich 'unsafe-eval' und eigene Frames
– der WordPress-Customizer funktioniert
ohne beides nicht. Diese Lockerung gilt ausschließlich hier. |
‚unsafe-eval‘ gibt es im öffentlichen Frontend nicht – nur im Customizer.
Externe Quellen sind im Frontend komplett gesperrt. Das geht, weil seotologie.de keine Google Fonts, keine eingebetteten Videos und keine externen Skripte lädt.
‚unsafe-inline‘ bleibt in allen drei Stufen – und genau das ist der Grund für das fehlende Plus.
Warum ‚unsafe-inline‘ bleiben muss
Eine WordPress-Seite gibt Inline-Code nicht nur aus dem Theme aus, sondern aus vielen Quellen gleichzeitig:
WordPress-Core, Theme (bei mir Astra), Cache-Plugin, Cookie-Consent und Analytics. Auf meiner eigenen
Startseite waren es bei der Messung rund zwei Dutzend Inline-Skripte und über hundert
style="…"-Attribute – fast alle aus fremdem Code.
Der saubere Weg ohne 'unsafe-inline' wären Nonces: Jedes erlaubte Inline-Element
bekommt ein einmaliges Token. Das scheitert bei WordPress an zwei Stellen:
Fremder Code: Den Inline-Skripten von Core und Plugins eine Nonce unterzuschieben, heißt, in deren Ausgabe einzugreifen. Das ist brüchig und bricht beim nächsten Update.
Style-Attribute: Nonces gelten nur für komplette <script>– und
<style>-Elemente – nicht für style="…"-Attribute an
einzelnen HTML-Elementen. Um sie ohne 'unsafe-inline' zu erlauben, müsste jedes einzelne
Attribut aus Core, Theme und Plugins verschwinden. Auf einer Plugin-basierten Seite ist das praktisch
unmöglich.
Was in meiner Hand liegt, gehe ich Schritt für Schritt an: Die Theme-Stylesheets sind in einer
zentralen CSS-Datei zusammengeführt, und neue oder überarbeitete Bausteine entstehen komplett ohne
style="…"-Attribute. Ältere Theme-Teile und meine Tools stelle ich nach und nach um –
erledigt ist das noch nicht.
Wichtig: Ein A+-Rating ist mit einem Plugin-basierten WordPress technisch nicht erreichbar. Das liegt nicht an der Sicherheit, sondern an der Architektur. Ein A-Rating ist die realistische Obergrenze für ein voll funktionsfähiges WordPress-Frontend.
Technische Voraussetzungen & Risiken
1. Apache & mod_headers
Damit die Sicherheits-Header korrekt ausgeliefert werden, muss auf deinem Server das Modul
mod_headers aktiviert sein. Bei modernen Hostern wie IONOS, Strato, All-Inkl oder
HostEurope ist das standardmäßig der Fall. Für die bereichsweise CSP brauchst du außerdem
Apache 2.4 oder neuer (wegen der <If>-Blöcke).
2. HSTS: Der stärkste, aber riskanteste Header
HSTS zwingt Browser, deine Seite ausschließlich über HTTPS zu laden – und das für die
Dauer des gesetzten max-age. Das erhöht die Sicherheit erheblich, bringt aber klare Risiken mit
sich:
Läuft dein SSL-Zertifikat ab, ist die Seite für Besucher komplett gesperrt.
Ein erzwungener HTTP-Aufruf ist nicht mehr möglich – auch für dich selbst nicht.
Mit includeSubDomains gilt der HTTPS-Zwang für alle Subdomains.
preload ist nur die Erlaubnis, deine Domain in die Preload-Liste der Browser einzutragen.
Trägst du sie dort ein, bekommst du sie nur mit Wochen bis Monaten Verzögerung wieder heraus. Lass
preload weg, wenn du dir nicht sicher bist.
3. Das CSP-Problem
Die Content-Security-Policy ist extrem wirkungsvoll, kann aber Funktionen blockieren, ohne dass du es
sofort bemerkst. Meine Konfiguration ist streng: default-src 'self' sperrt im
Frontend alles, was nicht von der eigenen Domain kommt.
Externe Dienste wie Google Fonts, YouTube, Analytics, Pixel oder Chat-Widgets musst du einzeln freigeben.
Plugins mit Inline-Skripten funktionieren nur dank 'unsafe-inline'.
Eine zu strenge CSP kann Layouts und Interaktionen beeinträchtigen.
Wichtig: Nach jeder Änderung die Browser-Konsole prüfen (F12 → Console).
4. Anpassen an deine Seite
Mein Setup ist auf seotologie.de zugeschnitten. Wenn du es übernimmst, prüfe diese Punkte:
| Header | Risiko für Layout/Funktion |
|---|---|
| Strict-Transport-Security | Hoch, wenn SSL nicht stabil ist. |
| X-Frame-Options | Mittel, wenn deine Seite auf anderen Domains eingebettet werden soll (z. B. in einem Kunden-Portal). |
| Permissions-Policy | Gering. Bei mir ist alles abgeschaltet, was die Seite nicht braucht – brauchst du Standort, Vollbild oder Zahlungen, gib sie frei. |
| Content-Security-Policy | Hoch, wenn du externe Dienste nutzt –
die musst du wegen
default-src 'self' einzeln ergänzen. |
| Cross-Origin-Resource-Policy | Mittel, wenn fremde Websites deine Bilder oder Dateien
direkt einbinden
sollen – same-site blockt das im Browser. |
Mein Header-Setup für die .htaccess (Stand 2026)
Genau diese Sicherheits-Header laufen auf seotologie.de. Der Abschnitt ist für Apache-Server optimiert und
nutzt setifempty (ab Apache 2.4.7), um Konflikte mit Hoster-Vorgaben (z. B. IONOS, Strato,
All-Inkl) zu vermeiden. Drei Hinweise, bevor du kopierst:
Die Einträge mit borlabs.io und scw.cloud gehören zu meinem
Cookie-Consent-Plugin. Nutzt du ein anderes, ersetze sie durch dessen Domains – oder entferne sie.
Lädst du Google Fonts, YouTube-Videos oder externe Skripte, musst du deren Domains in
style-src, font-src, script-src oder frame-src
ergänzen.
Der Block mod_setenvif ganz oben ist für Hoster wie IONOS gedacht, die HTTPS über einen
Proxy abwickeln. Ohne ihn kennt Apache die Variable HTTPS nicht, und der HSTS-Header mit
env=HTTPS wird nie gesendet. Er gehört an den Anfang der .htaccess.
Wenn du nach dem Einbau trotzdem kein „A“ erhältst, prüfe, ob ein Proxy wie Cloudflare eigene Header überschreibt.
# SECURITY HEADERS BY SEOTOLOGIE (Stand 2026)
# 0. HTTPS-Erkennung hinter Proxy (z. B. IONOS) - ganz oben in die .htaccess
<IfModule mod_setenvif.c>
SetEnvIf X-Forwarded-Proto "https" HTTPS=on
</IfModule>
<IfModule mod_headers.c>
# 1. Transport Security (HSTS)
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" env=HTTPS
# 2. Clickjacking & MIME Protection
Header always setifempty X-Frame-Options "SAMEORIGIN"
Header always setifempty X-Content-Type-Options "nosniff"
# 3. Privacy & Referrer Control
Header always set Referrer-Policy "strict-origin-when-cross-origin"
# 4. Deprecated / Legacy Controls
Header always set X-XSS-Protection "0"
Header always set X-Permitted-Cross-Domain-Policies "none"
# 5. Permissions Policy (alles aus, was die Seite nicht braucht)
Header always set Permissions-Policy "camera=(), microphone=(), geolocation=(), browsing-topics=(), fullscreen=(), payment=()"
# 6. Cross-Origin Policies
Header always set Cross-Origin-Opener-Policy "same-origin-allow-popups"
Header always set Cross-Origin-Embedder-Policy "unsafe-none"
Header always set Cross-Origin-Resource-Policy "same-site"
# 7. Content Security Policy
# Stufe 1 - Frontend (streng)
Header always set Content-Security-Policy "upgrade-insecure-requests; default-src 'self'; base-uri 'self'; form-action 'self'; frame-ancestors 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; font-src 'self'; media-src 'self' data:; connect-src 'self' https://stats.borlabs.io; frame-src 'none';"
# Stufe 2 - Backend (wp-admin, wp-login): zusätzlich Cookie-Consent-Cloud
<If "%{REQUEST_URI} =~ m#^/wp-(admin|login)#">
Header always set Content-Security-Policy "upgrade-insecure-requests; default-src 'self'; base-uri 'self'; form-action 'self'; frame-ancestors 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; font-src 'self'; media-src 'self' data:; connect-src 'self' https://cdn-private.borlabs.io https://borlabs.io https://api.borlabs.io https://service.borlabs.io https://stats.borlabs.io https://fr-par.scw.cloud; frame-src 'none';"
</If>
# Stufe 3 - Customizer: zusätzlich unsafe-eval und eigene Frames
<If "%{REQUEST_URI} =~ m#^/wp-admin/customize\.php#">
Header always set Content-Security-Policy "upgrade-insecure-requests; default-src 'self'; base-uri 'self'; form-action 'self'; frame-ancestors 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' data: blob:; style-src 'self' 'unsafe-inline' data: blob:; img-src 'self' data: blob:; font-src 'self'; media-src 'self' data:; connect-src 'self' https://cdn-private.borlabs.io https://borlabs.io https://api.borlabs.io https://service.borlabs.io https://stats.borlabs.io https://fr-par.scw.cloud; frame-src 'self' data: blob:;"
</If>
# 8. Cleanup
Header always unset X-Powered-By
Header always unset X-Pingback
Header unset Server
</IfModule>
FAQ: Die häufigsten Fragen
Bekomme ich damit ein A+-Rating?
Nein. Mit einem Plugin-basierten WordPress ist ein A+ realistisch nicht erreichbar: Core, Theme und
Plugins
geben Inline-Skripte und style-Attribute aus, die sich nicht per Nonce absichern
lassen. Ein
A-Rating ist die sinnvolle Obergrenze bei voller Funktionalität.
Warum ist X-XSS-Protection auf „0“?
Der alte XSS-Filter in Browsern ist veraltet und kann mehr schaden als nutzen. Moderne Absicherung erfolgt über CSP.
Funktionieren YouTube, Google Fonts und externe Widgets noch?
Mit meinem Setup nicht automatisch: default-src 'self' sperrt alles Externe. Du musst
die
Domains gezielt freigeben – etwa fonts.googleapis.com in style-src und
fonts.gstatic.com in font-src für Google Fonts oder
www.youtube-nocookie.com in frame-src für Videos. Ich brauche das nicht,
weil
seotologie.de mit Systemschriften arbeitet und nichts Externes einbettet.
Warum ist ‚unsafe-inline‘ erlaubt?
In der Theorie unsicher, in der Praxis aber für WordPress-Core, das Theme und viele Plugins zwingend notwendig. Ohne ‚unsafe-inline‘ wäre das Frontend defekt.
Warum drei verschiedene CSPs statt einer?
Weil jede Lockerung nur dort gelten soll, wo sie wirklich gebraucht wird. Das öffentliche Frontend –
der
Teil, den Angreifer erreichen – bekommt die strengste Stufe. Das Backend braucht zusätzlich die
Cloud-Dienste des Cookie-Consent, der Customizer zusätzlich 'unsafe-eval'.
Kann ich ‚unsafe-eval‘ entfernen?
Im Frontend brauchst du es in der Regel nicht – bei mir ist es dort gar nicht gesetzt. Der
WordPress-Customizer benötigt es allerdings, deshalb erlaube ich es nur auf
/wp-admin/customize.php. Nutzt ein Plugin eval-ähnliche Konstrukte, musst du es dort
ebenfalls erlauben.
Was passiert, wenn ein Plugin eval() nutzt?
Dann blockiert die CSP das Plugin. In diesem Fall muss ‚unsafe-eval‘ ergänzt werden – oder das Plugin ersetzt werden.
Warum ist COEP auf unsafe-none gesetzt?
Mit require-corp dürfte die Seite nur noch fremde Ressourcen laden, die das ausdrücklich
erlauben. Eingebettete Videos, Google Fonts, Gravatar-Bilder und viele Plugin-Dienste würden dann
blockiert. Vollständige Cross-Origin-Isolation ist im WordPress-Umfeld nicht praktikabel.
Kann ich die Header auch per Plugin setzen?
Ja, aber nicht empfohlen. Ein Plugin setzt Header per PHP – und PHP läuft nicht, wenn ein
Cache-Plugin
die fertige HTML-Datei direkt ausliefert oder der Server Bilder, CSS und JavaScriptJavaScriptJavaScript ist eine Programmiersprache, die Webseiten interaktiv macht. Während HTML das Grundgerüst und CSS das Design liefert, sorgt JavaScript für Dynamik. Wenn du beispielsweise auf…Mehr lesen schickt. Dann
fehlen die
Header genau dort. Dazu kommen doppelte Header, wenn Server und Plugin beide senden. Die
.htaccess greift bei jeder Antwort.
Warum verschwindet der Server-Header bei mir nicht?
Der Befehl Header unset Server (ganz unten im Code) funktioniert leider nicht auf jedem
Apache-Server. Oft fügt der Webserver diesen Header erst im allerletzten Schritt hinzu, nachdem die
.htaccess bereits verarbeitet wurde. Um den Server-Header zuverlässig zu verbergen,
brauchst du
in der Regel Zugriff auf die Hauptkonfiguration (ServerTokens Prod). Es schadet aber
nicht, es
über die .htaccess zu versuchen.
Kann diese Konfiguration meine Seite „zerschießen“?
Ja, wenn deine Seite externe Ressourcen nutzt, die nicht freigegeben sind – meine CSP ist bewusst
streng.
Teste deshalb zuerst mit Content-Security-Policy-Report-Only (siehe Troubleshooting)
und
gib fehlende Domains gezielt frei.
Warum sehe ich keine Änderungen nach dem Speichern?
Browser und CDNs speichern ganze Antworten samt Headern. Cache leeren oder privaten Modus nutzen. Bei HSTS kann der Browser alte Werte über Monate behalten.
Gibt es eine sicherere Alternative zu ‚unsafe-inline‘?
Für Skripte ja: Nonces oder Hashes. Die müssten aber auch in die Ausgabe von Core und Plugins, die du
nicht
kontrollierst. Für style-Attribute helfen Nonces gar nicht – sie gelten nur für
komplette
<script>– und <style>-Elemente. Deshalb ist ‚unsafe-inline‘
bei
WordPress die einzige realistische Option.
Was ist der Unterschied zwischen always set und setifempty?
set ersetzt einen bestehenden Header, setifempty setzt ihn nur, wenn noch
keiner
existiert – ideal bei Hostern, die eigene Header senden. Das Wort always bedeutet etwas
anderes:
Der Header wird auch bei Weiterleitungen und Fehlerseiten (3xx, 4xx, 5xx) gesendet, nicht nur bei
erfolgreichen Antworten. Pro-Tipp: Beide lassen sich als
always setifempty
kombinieren (wie in meinem Code-Schnipsel oben).
Troubleshooting: Was tun, wenn etwas nicht funktioniert?
1. Die Seite lädt, aber Funktionen fehlen (Slider, Menüs, Buttons)
Browser-Konsole öffnen (F12 → Console). Wenn CSP-Fehler angezeigt werden, blockiert die CSP Skripte oder Styles. Dann betroffene Domains freigeben.
2. YouTube, Google Maps oder externe Widgets laden nicht
Prüfen, ob die eingebundenen Domains in frame-src, script-src oder
img-src erlaubt sind. Mit frame-src 'none' wie bei mir sind eingebettete
Inhalte
grundsätzlich gesperrt.
3. Das Backend (WP-Admin) funktioniert nicht mehr richtig
Dann ist die CSP für das Backend zu streng. Genau dafür gibt es in meinem Setup eine eigene Stufe für
/wp-admin und den Customizer – dort kannst du Backend-Dienste freigeben, ohne das
Frontend
aufzuweichen.
4. Nach Aktivierung von HSTS ist die Seite nicht erreichbar
SSL prüfen, Zertifikat erneuern. HSTS kann nicht kurzfristig deaktiviert werden – der Browser speichert den Zustand.
5. Ein Plugin funktioniert plötzlich nicht mehr
Konsole prüfen. Wenn eval oder Inline-Skripte blockiert werden, muss die CSP angepasst oder das Plugin ersetzt werden.
6. Ich möchte testen, ohne etwas zu blockieren
CSP als Content-Security-Policy-Report-Only senden. So werden Verstöße geloggt, aber
nichts
blockiert.
7. HTTPS wird weiter erzwungen, obwohl ich HSTS entfernt habe
Der Browser speichert HSTS bis zum Ablauf von max-age. Testen im privaten Modus oder mit
anderem
Browser.
Mein Fazit
Sicherheit ist kein Zufall, sondern Konfiguration. Mit diesem Setup erreicht seotologie.de die Note A – alle sechs bewerteten Header aktiv, die CSP im Frontend so streng wie möglich. Das fehlende Plus ist keine Sicherheitslücke, sondern die Architektur von WordPress. Und das Frontend und Backend bleiben dabei voll funktionsfähig.
Wie steht deine eigene Seite da? Mein Security-Header-Check prüft alle relevanten Header in Sekunden – kostenlos und ohne Anmeldung.
Zuletzt aktualisiert am .