Guide

WordPress Security-Header: was du setzen solltest und was deine Seite brechen kann

Ein Sicherheitsscan meldet fehlende Header: HSTS, Content-Security-Policy, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy. Das sind Zeilen, die dein Server mit jeder Seite mitschickt und die dem Browser sagen, wie streng er die Seite behandeln soll. WordPress selbst sendet auf den Seiten, die Besucher sehen, fast keine davon. Drei lassen sich heute ohne echtes Risiko ergänzen. Die anderen drei brauchen einen kurzen Plan, denn ein falscher Wert kann Besucher aussperren oder deine eigenen Skripte blockieren. Dieser Leitfaden behandelt jeden einzelnen, wo du ihn in WordPress setzt und warum Header, die letzten Monat noch da waren, wieder verschwinden.

Was Security-Header sind und warum ein fehlender zählt

Jede Antwort deines Servers beginnt mit Headern: Inhaltstyp, Cache-Regeln, Cookies. Security-Header sind ein paar weitere, die Schutzfunktionen einschalten, die der Browser schon hat, aber nur nutzt, wenn die Seite danach fragt. X-Frame-Options verhindert, dass eine fremde Seite deine in einem unsichtbaren Frame lädt und Besucher zu Klicks verleitet (Clickjacking). HSTS sagt dem Browser, nur HTTPS zu verwenden – auch wenn jemand die Adresse ohne eintippt. Content-Security-Policy legt fest, woher Skripte laden dürfen, und begrenzt so, was eingeschleuster Code anrichten kann.

Ein fehlender Header ist für sich keine Lücke und bedeutet nicht, dass die Seite gehackt wurde. Er bedeutet, dass eine Abwehr des Browsers ausgeschaltet ist. Deshalb melden Scanner ihn als Warnung, nicht als Fehler – und deshalb lohnt es sich, die sicheren zu setzen und den Rest zu planen, statt die ganze Liste zu ignorieren.

Der WordPress-Kern sendet X-Frame-Options: SAMEORIGIN (und eine passende frame-ancestors-Regel) auf der Login-Seite und in wp-admin. Die öffentliche Seite – die Seiten, die ein Scan prüft – bekommt keinen der sechs, solange nicht dein Hoster, dein CDN oder ein Plugin sie ergänzt.

So siehst du, welche deine Seite sendet

Im Browser: Startseite öffnen, dann Entwicklertools → Netzwerk, neu laden, die erste Anfrage (die Seite selbst) anklicken und die Antwort-Header lesen. Im Terminal folgt der Befehl unten Weiterleitungen wie ein Browser und gibt nur die sechs Security-Header aus. Was in der Ausgabe fehlt, fehlt auf der Seite.

Prüfe die endgültige Seite nach allen Weiterleitungen, über HTTPS. Ein Header, den die http://-Adresse sendet, die https://-Seite aber nicht, fehlt für Besucher trotzdem.

curl -sIL https://example.com/ | grep -iE "strict-transport-security|content-security-policy|x-frame-options|x-content-type-options|referrer-policy|permissions-policy"

Die drei, die du heute setzen kannst

X-Content-Type-Options: nosniff verhindert, dass der Browser den Dateityp rät: Eine als Text ausgelieferte Datei wird nicht als Skript ausgeführt, und ein Skript oder Stylesheet mit falschem Inhaltstyp wird blockiert. Auf einer normalen WordPress-Seite ändert sich nichts, weil WordPress, der Webserver und gut gebaute Plugins schon korrekte Typen senden.

X-Frame-Options: SAMEORIGIN erlaubt deinen eigenen Seiten, einander einzubetten, verbietet es aber jeder anderen Seite. Kaputt geht nur eine Seite, die du absichtlich auf einer anderen Domain einbettest – etwa ein Buchungsformular auf der Seite eines Partners. In dem Fall nutzt du stattdessen die frame-ancestors-Direktive der Content-Security-Policy, die eine Liste erlaubter Seiten annimmt.

Referrer-Policy: strict-origin-when-cross-origin gibt anderen Seiten nur deine Domain weiter, nicht die volle Adresse der Seite, von der ein Besucher kam, und von HTTPS zu HTTP gar nichts. Genau so verhalten sich aktuelle Browser auch ohne gesetzte Richtlinie; der Header macht das Verhalten vor allem ausdrücklich. Von den sechs ist er am wenigsten riskant, wenn er fehlt, und am leichtesten zu setzen.

Unter Apache (die meisten Shared-Hostings für WordPress) gehören diese Zeilen in die .htaccess oberhalb des Blocks # BEGIN WordPress – WordPress überschreibt nur, was zwischen seinen eigenen Markierungen steht, die Zeilen bleiben also erhalten, wenn Permalinks gespeichert werden. Die Zeile Permissions-Policy wird weiter unten erklärt; lass sie weg, bis du den Abschnitt gelesen hast.

<IfModule mod_headers.c>
  Header set X-Content-Type-Options "nosniff"
  Header set X-Frame-Options "SAMEORIGIN"
  Header set Referrer-Policy "strict-origin-when-cross-origin"
  Header set Permissions-Policy "camera=(), microphone=(), geolocation=()"
</IfModule>

HSTS: erst, wenn HTTPS überall funktioniert

Strict-Transport-Security lässt den Browser für max-age Sekunden speichern, dass die Seite nur über HTTPS erreichbar ist. Das verhindert die erste unverschlüsselte Anfrage – die, die ein Angreifer im öffentlichen WLAN abfangen kann – und macht aus Zertifikatswarnungen harte Fehler, die Besucher nicht wegklicken können. Browser ignorieren den Header, wenn er über reines HTTP ankommt; er wirkt also nur von einer HTTPS-Seite aus.

Das Risiko ist das Gedächtnis. Läuft das Zertifikat ab oder läuft eine Subdomain noch über HTTP, verweigern Browser, die den Header gesehen haben, die Seite, bis max-age abgelaufen ist – und abschalten (max-age=0) kannst du ihn nur für Browser, die die Seite wieder über HTTPS erreichen. Führe ihn deshalb schrittweise ein: zuerst max-age=300 (fünf Minuten), alle Seiten und Subdomains prüfen, dann auf einen Tag, eine Woche und schließlich 31536000 (ein Jahr) erhöhen. includeSubDomains erst ergänzen, wenn jede Subdomain – Mail, Shop, Staging – HTTPS ausliefert.

Die Direktive preload ist eine eigene Entscheidung. Sie bittet Browser, deine Domain in ihre eingebaute HTTPS-only-Liste aufzunehmen; dafür braucht es ein Jahr max-age plus includeSubDomains, und von der Liste wieder herunterzukommen dauert lange. Lass sie weg, wenn du nicht sicher bist. Steht die Seite hinter Cloudflare, ist HSTS eine Einstellung unter SSL/TLS → Edge Certificates statt einer Serverzeile.

Content-Security-Policy: zuerst im Report-only-Modus

Eine vollständige Content-Security-Policy listet jede Herkunft auf, von der Skripte, Styles, Schriften, Bilder und Frames laden dürfen. Sie ist von den sechs der stärkste Schutz gegen eingeschleusten Code – und der, der eine WordPress-Seite am ehesten bricht: Themes, Page-Builder, Analytics, Consent-Banner, Chat-Widgets und Zahlungsbuttons laden alle Skripte von irgendwoher, oft inline. Eine strenge Richtlinie aus einem Tutorial zu kopieren, blockiert einige davon.

Sende sie zuerst als Content-Security-Policy-Report-Only. Der Browser erzwingt nichts und protokolliert jeden Verstoß in der Konsole, sodass du die Seite durchklicken – auch den Checkout – und jede Herkunft ergänzen kannst, die du wirklich brauchst. Benenne den Header erst in Content-Security-Policy um, wenn die Konsole ruhig bleibt.

Eine kurze Richtlinie, die selten etwas bricht, ist ein vernünftiger erster erzwungener Schritt, während du an der vollständigen arbeitest: object-src 'none'; base-uri 'self'; frame-ancestors 'self'. Sie blockiert alte Plugin-Einbettungen, verhindert, dass eingeschleuster Code das Ziel relativer Links ändert, und erledigt dieselbe Aufgabe wie X-Frame-Options: SAMEORIGIN.

Setze sie als Header. Eine Richtlinie in einem <meta http-equiv>-Tag funktioniert für die meisten Direktiven, aber frame-ancestors wird dort ignoriert, und Werkzeuge, die Antwort-Header lesen, sehen sie nicht.

Permissions-Policy: abschalten, was du nicht nutzt

Permissions-Policy legt fest, welche Browserfunktionen – Kamera, Mikrofon, Standort und andere – die Seite und alles, was sie einbettet, anfragen dürfen. camera=(), microphone=(), geolocation=() schaltet diese drei auf der ganzen Seite ab, sodass ein eingeschleustes Skript oder eine eingebettete Anzeige Besucher nicht danach fragen kann.

Liste nur Funktionen auf, von denen du weißt, dass die Seite sie nicht nutzt. Eine Filialsuche, die nach dem Standort des Besuchers fragt, braucht geolocation=(self) statt geolocation=(); ein Plugin für Videoanrufe oder Aufnahmen braucht Kamera und Mikrofon. Prüfe die Seiten mit solchen Funktionen, nachdem du den Header gesetzt hast.

Wo du sie in WordPress setzt

Es gibt drei Orte, und je weiter oben, desto mehr decken sie ab. Der Webserver (.htaccess unter Apache, der server-Block unter Nginx) deckt jede Antwort ab, auch Bilder, Skripte und gecachte Seiten. Ein CDN vor der Seite deckt alles ab, was durch es läuft. Innerhalb von WordPress – ein Sicherheits-Plugin, ein paar Zeilen am Hook send_headers oder Relvatos "Add safe security headers" – sind nur die Seiten abgedeckt, die WordPress selbst erzeugt; eine Seite, die ein Cache ausliefert, bevor WordPress vollständig lädt, kann ohne sie hinausgehen. Als schnelle Lösung ist das in Ordnung, prüfe aber das Ergebnis auf der Live-Startseite.

Unter Nginx verwendest du add_header mit always, damit der Header auch auf Fehlerseiten gesendet wird. Achte auf eine Falle: Ein location-Block mit einem eigenen add_header erbt die aus dem server-Block nicht. Jemand ergänzt einen Cache-Header in einer location, und die Security-Header verschwinden dort unbemerkt.

Setze jeden Header an genau einem Ort. Zwei Ebenen, die denselben Header ergänzen, senden ihn doppelt, und zwei Content-Security-Policy-Header werden beide erzwungen – die wirksame Richtlinie ist dann strenger als jede einzelne.

add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;

Warum Header wieder verschwinden

Header werden selten absichtlich entfernt. Sie verschwinden, wenn sich der Ort ändert, der sie gesetzt hat: ein Umzug zu einem neuen Hoster (Nginx liest die .htaccess überhaupt nicht, jede Regel darin hört also auf zu wirken), ein neues CDN oder eine zurückgesetzte CDN-Einstellung, ein Caching-Plugin, das gegen eines getauscht wird, das Seiten ausliefert, bevor WordPress lädt, ein deaktiviertes Sicherheits-Plugin oder eine Option, die ein Update zurückgesetzt hat, oder ein neuer location-Block in Nginx, der sie nicht mehr erbt.

Nichts davon erzeugt einen Fehler. Die Seite sieht gleich aus, also merkt man es nur, wenn man die Header nach jeder Änderung erneut prüft – genau das, was nach jedem Update niemand von Hand macht.

Wie Relvato es erkennt

Relvatos Monitor Exposure scan ruft deine Startseite wie ein Browser ab, folgt Weiterleitungen und liest die Antwort-Header. Er funktioniert auf jeder Website, nicht nur unter WordPress. Jeder fehlende Header ist eine eigene Warnung – "Missing security header: HSTS", "Missing security header: Content-Security-Policy" und so weiter – bei einem Lauf, der ansonsten besteht. Weil jede einzeln ist, kannst du bei einem Header, gegen den du dich vorerst entschieden hast, etwa CSP, auf "Ignore this warning" klicken und hörst trotzdem von den anderen. Er liest nur Header; eine Richtlinie in einem Meta-Tag zählt nicht.

Unter WordPress mit dem Relvato-Plugin bekommen die drei sicheren Header "Fix in WordPress" neben der Warnung. In WordPress → Relvato schaltet ein Klick "Add safe security headers" ein: X-Content-Type-Options: nosniff, Referrer-Policy: strict-origin-when-cross-origin und X-Frame-Options: SAMEORIGIN, jeweils nur, wenn die Seite ihn nicht schon sendet. "Switch off" schaltet es dort wieder ab. HSTS, Content-Security-Policy und Permissions-Policy werden nie für dich gesetzt, weil ein falscher Wert Seiten bricht – siehe was Relvato nicht für dich behebt.

Im Free-Plan klickst du auf Run, wann immer du den Scan möchtest, oder planst ihn wöchentlich. Pro führt deine Monitore nach jedem Update von selbst erneut aus, sodass ein Header, den ein Plugin-Update oder ein Hosterwechsel entfernt hat, wieder als Warnung erscheint, ohne dass jemand daran denken muss nachzusehen.

Die sechs Security-Header im Überblick

HeaderWas er tutEin sicherer StartwertKann er etwas brechen?
X-Content-Type-OptionsVerhindert, dass der Browser Dateitypen rätnosniffUnter WordPress fast nie
X-Frame-OptionsVerhindert, dass fremde Seiten deine einbetten (Clickjacking)SAMEORIGINNur Seiten, die du auf anderen Domains einbettest
Referrer-PolicyBegrenzt, was andere Seiten über die Herkunftsseite eines Besuchers erfahrenstrict-origin-when-cross-originNein – das ist der Browser-Standard
Permissions-PolicySchaltet Kamera, Mikrofon, Standort und andere Funktionen abcamera=(), microphone=(), geolocation=()Ja, wenn eine Seite eine dieser Funktionen nutzt
Strict-Transport-Security (HSTS)Lässt Browser nur HTTPS verwendenmax-age=300, schrittweise erhöhtJa – sperrt HTTP-Subdomains und abgelaufene Zertifikate aus
Content-Security-PolicyLegt fest, woher Skripte, Styles und Frames laden dürfenZuerst Report-Only; object-src 'none'; base-uri 'self'; frame-ancestors 'self'Ja – blockiert am ehesten deine eigenen Skripte

Fragen und Antworten

Welchen Security-Header sollte ich zuerst setzen?

X-Content-Type-Options, X-Frame-Options und Referrer-Policy, zusammen: Sie sind auf fast jeder WordPress-Seite sicher und brauchen nur ein paar Zeilen. Dann Permissions-Policy für Funktionen, die du nicht nutzt, dann HSTS schrittweise und Content-Security-Policy zuletzt, zuerst im Report-only-Modus.

Helfen Security-Header bei der SEO?

Google führt Security-Header nicht als Ranking-Signal auf; HTTPS ist eines. HSTS hilft, indem es Besucher auf HTTPS hält. Der eigentliche Grund für die Header ist der Schutz der Besucher, nicht das Ranking.

Kann ein Plugin sie für mich setzen?

Ja, und mehrere Sicherheits-Plugins tun das. Ein Plugin setzt sie nur auf Seiten, die WordPress erzeugt; prüfe danach die Live-Startseite – ein Seiten-Cache oder ein CDN kann Seiten ohne sie ausliefern. Setze jeden Header nur an einem Ort, damit er nicht doppelt gesendet wird.

Ich habe ein CSP-Meta-Tag ergänzt. Warum wird der Header weiter als fehlend gemeldet?

Der Scan liest die Antwort-Header, und eine <meta http-equiv>-Richtlinie ist keiner. Browser wenden die meisten Direktiven aus dem Meta-Tag an, aber nicht frame-ancestors. Als Header gesendet, deckt die Richtlinie alles ab.

Heißt ein fehlender Security-Header, dass meine Seite gehackt wurde?

Nein. Er heißt, dass ein Browserschutz ausgeschaltet ist. Wenn du einen Einbruch befürchtest, sehen die Anzeichen anders aus – siehe die Checkliste für gehackte WordPress-Seiten.

Quellen

Weiterführende Artikel
Guide

Erfahre am selben Tag, wenn ein Header fehlt.

Relvatos Exposure scan prüft deine Header zusammen mit allem anderen, was eine Seite preisgibt, und schlägt unter WordPress die sicheren vor, gesetzt mit einem Klick in WordPress → Relvato – mit Undo.