Technik · 11 Min. Lesezeit

Security-Header prüfen: HSTS, CSP & Co. richtig setzen

Kurz erklärt

Security-Header sind HTTP-Antwortkopfzeilen, mit denen Ihr Server dem Browser Sicherheitsregeln vorgibt: etwa „nur per HTTPS verbinden“ (HSTS), „Skripte nur von diesen Quellen laden“ (CSP) oder „Dateitypen nicht erraten“ (nosniff). Sie ersetzen keine sichere Anwendung, schließen aber ganze Angriffsklassen ab und lassen sich mit einem einzigen curl-Aufruf prüfen.

Das Wichtigste in Kürze

  • Security-Header kosten keine Leistung und keinen Code, sie sind eine Serverkonfiguration, die der Browser durchsetzt.
  • Die wichtigsten fünf: Strict-Transport-Security, Content-Security-Policy, X-Content-Type-Options, Referrer-Policy und Permissions-Policy.
  • HSTS und CSP nie ungetestet scharf schalten: HSTS merkt sich der Browser monatelang, eine zu strenge CSP legt Skripte lahm.
  • In nginx gilt: add_header immer mit always und nicht in verschachtelten Blöcken vergessen, sonst verschwinden Header still.
  • Prüfen Sie mit curl -sI und wiederholen Sie die Prüfung nach jedem Deployment, Relaunch oder CDN-Wechsel.

Was sind Security-Header und warum lohnt sich die Prüfung?

Jede HTTP-Antwort besteht aus Statuszeile, Kopfzeilen (Headern) und optional einem Inhalt (die Grundlagen stehen in HTTP-Statuscodes erklärt). Security-Header sind solche Kopfzeilen, die den Browser anweisen, bestimmte Schutzmechanismen zu aktivieren. Der Server liefert die Regel mit, der Browser setzt sie durch. Ein Angreifer, der etwa eine Schwachstelle für Skript-Einschleusung (Cross-Site-Scripting, XSS) findet, scheitert dann unter Umständen daran, dass der Browser fremde Skripte gar nicht erst ausführt.

Warum sollte man das regelmäßig prüfen, statt es einmal einzurichten? Weil Header auf dem Weg vom Server zum Besucher verloren gehen oder sich ändern: ein neuer Hoster, ein CDN, ein Relaunch mit neuer Serverkonfiguration, ein WordPress-Plugin, das Header überschreibt, oder ein nginx-Block, der geerbte Header stillschweigend verwirft. Die Website läuft dabei weiter, nur der Schutz fehlt. Im Gegensatz zu einem Ausfall merkt das niemand, bis es jemand testet. Genau deshalb gehört die Prüfung in einen wiederkehrenden Ablauf.

Wichtig für die Einordnung: Security-Header sind eine zusätzliche Verteidigungslinie („Defense in Depth“). Sie beheben keine Sicherheitslücken in Ihrem Code, sie mindern deren Folgen. Das OWASP Secure Headers Project, das wir in den Quellen verlinken, führt die gängigen Header und empfohlene Werte auf.

Welche Security-Header gibt es und welche Werte sind sinnvoll?

Die folgende Tabelle fasst die Header zusammen, die in der Praxis relevant sind. Die Werte sind Ausgangspunkte für typische Websites, keine Pauschalrezepte; vor allem CSP muss auf Ihre Seite zugeschnitten werden.

HeaderSchutzwirkungSinnvoller StartwertRisiko bei Fehlkonfiguration
Strict-Transport-SecurityErzwingt HTTPS, verhindert Downgrade auf HTTPmax-age=31536000; includeSubDomainsSubdomains ohne HTTPS werden unerreichbar
Content-Security-PolicyBegrenzt Quellen für Skripte, Styles, Frames u. a.; mindert XSSErst Content-Security-Policy-Report-Only, dann eigene PolicySkripte, Schriften oder Bezahlformulare werden blockiert
X-Content-Type-OptionsVerhindert „MIME-Sniffing“, also das Erraten des DateitypsnosniffSehr gering; falsche Content-Type-Angaben fallen auf
Referrer-PolicySteuert, welche URL-Teile an Zielseiten übermittelt werdenstrict-origin-when-cross-originGering; Auswertungen, die den vollen Referrer brauchen, ändern sich
Permissions-PolicySchaltet Browserfunktionen (Kamera, Mikrofon, Standort) ab oder freiz. B. camera=(), microphone=(), geolocation=()Eigene Funktionen (Karte, Video-Chat) funktionieren nicht mehr
X-Frame-Options bzw. CSP frame-ancestorsVerhindert Einbettung in fremde Seiten (Clickjacking)SAMEORIGIN oder frame-ancestors 'self'Legitime Einbettung (z. B. Kundenportal) bricht
Cross-Origin-Opener-Policy u. a.Isoliert Browsing-Kontexte gegenüber fremden FensternOptional, nur nach Test (same-origin)Pop-ups und Zahlungs-Fenster können ihre Verbindung verlieren

Wie funktioniert HSTS und worauf müssen Sie achten?

HTTP Strict Transport Security (HSTS) ist in RFC 6797 beschrieben. Der Server sendet den Header einmal über HTTPS, der Browser merkt sich die Anweisung für die angegebene Zeit und stellt Anfragen an diese Domain danach intern auf HTTPS um, ohne zuvor eine unsichere HTTP-Anfrage abzusetzen. Das schließt die Lücke, die eine reine Weiterleitung von HTTP auf HTTPS offen lässt: Die allererste Anfrage könnte sonst abgefangen werden. Über HTTP gesendet wird der Header laut Standard ignoriert.

Strict-Transport-Security: max-age=31536000; includeSubDomains

max-age gibt die Gültigkeit in Sekunden an: 31.536.000 Sekunden entsprechen 365 Tagen. includeSubDomains dehnt die Regel auf alle Subdomains aus, und das ist der Fallstrick: Hängt irgendwo intranet.example.de oder ein altes shop-alt.example.de ohne gültiges Zertifikat, ist es für Browser, die HSTS gespeichert haben, nicht mehr erreichbar, und zwar ohne Ausweichmöglichkeit, denn Zertifikatswarnungen lassen sich bei aktivem HSTS nicht wegklicken.

Zusätzlich gibt es die Option preload. Sie signalisiert, dass die Domain in die fest in Browser eingebauten Preload-Listen aufgenommen werden darf. Das ist faktisch schwer rückgängig zu machen (Entfernung dauert, bis Browser-Updates verteilt sind). Wir empfehlen preload nur, wenn Sie alle Subdomains dauerhaft HTTPS-fähig halten und die Konsequenzen verstanden haben; die genauen Aufnahmebedingungen sollten Sie bei den Betreibern der Preload-Liste nachlesen, da sie sich ändern können.

Beispielrechnung

So führen Sie HSTS gefahrlos ein: Beginnen Sie mit max-age=300 (5 Minuten) und prüfen Sie Haupt- und Subdomains. Erhöhen Sie dann stufenweise: 86.400 Sekunden (1 Tag), 604.800 (7 Tage), 2.592.000 (30 Tage) und schließlich 31.536.000 (365 Tage). Wenn Sie in Stufe 3 einen Fehler entdecken, hat der längste Browser-Cache höchstens 7 Tage Restwirkung; bei sofortigem Sprung auf ein Jahr wären es bis zu 365 Tage, in denen betroffene Besucher eine nicht erreichbare Subdomain haben, bis der Header mit max-age=0 korrigiert und tatsächlich von den Browsern erneut abgerufen wurde.

Wie setzen Sie eine Content-Security-Policy ohne Seitenschäden ein?

Die Content-Security-Policy (CSP) ist der mächtigste und zugleich heikelste Header. Sie besteht aus Direktiven, die je Ressourcentyp erlaubte Quellen festlegen (Dokumentation: MDN Content-Security-Policy in den Quellen). Beispiel einer strengen, aber realistischen Startpolicy für eine Seite mit eigenen Dateien und einem externen Analysedienst:

Content-Security-Policy: default-src 'self'; script-src 'self' https://analytics.example.com; img-src 'self' data:; style-src 'self'; frame-ancestors 'self'; base-uri 'self'; form-action 'self'

default-src 'self' erlaubt als Rückfall nur Ressourcen der eigenen Herkunft. frame-ancestors regelt, wer die Seite einbetten darf, base-uri und form-action verhindern manipulierte Basis-URLs und fremde Formularziele. Die gefährlichsten Werte sind 'unsafe-inline' und 'unsafe-eval' bei script-src: Sie erlauben genau das, was XSS ausnutzt, und höhlen den Schutz weitgehend aus. Besser sind Nonces (ein pro Antwort zufällig erzeugter Wert, den erlaubte Inline-Skripte tragen) oder Hashes.

Der sichere Weg: erst Report-Only

Mit Content-Security-Policy-Report-Only meldet der Browser Verstöße, blockiert aber nichts. Betreiben Sie die Policy einige Tage so, werten Sie die Konsole (Entwicklertools) oder einen Report-Endpunkt aus und ergänzen Sie erlaubte Quellen. Erst danach stellen Sie auf den scharfen Header um. Typische Überraschungen sind eingebundene Schriften von Fremdservern, Zahlungsanbieter-Frames, Tag-Manager, die Skripte nachladen, und Inline-Event-Handler wie onclick in älteren Templates.

Welche weiteren Header lohnen sich?

X-Content-Type-Options

Mit X-Content-Type-Options: nosniff darf der Browser den Dateityp nicht aus dem Inhalt erraten, sondern muss sich an den Content-Type halten. Das verhindert, dass etwa ein hochgeladenes „Bild“, das tatsächlich Skript enthält, ausgeführt wird. Der Header ist nahezu risikofrei; er deckt aber falsch ausgelieferte Dateitypen auf, etwa eine CSS-Datei mit text/plain.

Referrer-Policy

Beim Klick auf einen Link sendet der Browser standardmäßig die Herkunftsseite mit. Referrer-Policy: strict-origin-when-cross-origin übermittelt an fremde Seiten nur die Domain (ohne Pfad und Parameter) und nichts, wenn von HTTPS auf HTTP gewechselt wird. Das schützt Informationen wie Sitzungs- oder Suchparameter in URLs. Moderne Browser verwenden diesen Wert inzwischen häufig ohnehin als Standard; ihn explizit zu setzen macht das Verhalten unabhängig vom Browser.

Permissions-Policy

Damit deaktivieren Sie Funktionen, die Ihre Seite nicht braucht, auch für eingebettete Frames: Permissions-Policy: camera=(), microphone=(), geolocation=(). Eine Liste der unterstützten Funktionen ändert sich mit den Browsern; setzen Sie nur Direktiven, die Sie kennen.

Clickjacking-Schutz

Soll Ihre Seite nicht in fremden Frames erscheinen, nutzen Sie frame-ancestors in der CSP. Als Ergänzung für sehr alte Browser wird weiterhin X-Frame-Options: SAMEORIGIN (oder DENY) gesetzt. Gilt beides, hat frame-ancestors in modernen Browsern Vorrang.

Welche Header sind veraltet oder verraten zu viel?

Nicht jeder Header, den ältere Anleitungen nennen, ist heute sinnvoll:

  • X-XSS-Protection: Der eingebaute XSS-Filter alter Browser ist abgeschaltet oder entfernt worden, und er hatte selbst Schwachstellen. Wenn Sie den Header setzen, dann mit 0; meist genügt es, ihn wegzulassen und auf CSP zu setzen.
  • Server und X-Powered-By: Sie nennen Software und häufig Versionen (nginx/1.24.0, PHP/8.2.x). Das ist kein Sicherheitsmerkmal an sich, erleichtert Angreifern aber gezielte Suche nach bekannten Lücken. Verbergen Sie die Details: nginx server_tokens off;, Apache ServerTokens Prod, PHP expose_php = Off.
  • Public-Key-Pins (HPKP): Wurde aus den Browsern entfernt; senden Sie ihn nicht mehr.
  • Expect-CT: Hat durch die allgemeine Pflicht zur Zertifikatstransparenz seine Bedeutung verloren; kann entfallen.

Wie setzen Sie Security-Header in nginx und Apache?

Die folgenden Auszüge sind Ausgangspunkte. Passen Sie die CSP an Ihre Seite an.

nginx

server {
    listen 443 ssl;
    server_name www.example.de;

    server_tokens off;

    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
    add_header Content-Security-Policy-Report-Only "default-src 'self'" always;
}

Das Schlüsselwort always sorgt dafür, dass der Header auch bei Fehlerantworten (404, 500) gesendet wird. Ohne always setzt nginx ihn nur bei Statuscodes wie 200, 204, 301, 302, 304 und anderen Erfolgs- bzw. Umleitungsantworten. Wichtigster Fallstrick: add_header wird von einer Ebene an die nächste nur vererbt, wenn dort kein eigenes add_header steht. Definieren Sie in einem location-Block einen eigenen Header (z. B. Cache-Control), gehen alle Header aus dem server-Block für diese Location verloren. Wiederholen Sie die Security-Header dort, oder binden Sie sie per include in jede Location ein.

Apache

<IfModule mod_headers.c>
    Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
    Header always set X-Content-Type-Options "nosniff"
    Header always set Referrer-Policy "strict-origin-when-cross-origin"
    Header always set Permissions-Policy "camera=(), microphone=(), geolocation=()"
    Header always set Content-Security-Policy-Report-Only "default-src 'self'"
</IfModule>
ServerTokens Prod
ServerSignature Off

In Apache muss das Modul mod_headers aktiv sein. Auf Shared Hosting können Sie die Zeilen häufig in die .htaccess legen (ohne ServerTokens, das nur in der Serverkonfiguration gilt). Läuft PHP hinter einem Proxy oder einem CDN, kann das jeweilige Panel zusätzliche eigene Header setzen oder Ihre überschreiben; prüfen Sie immer das Ergebnis von außen.

Wie prüfen Sie die Header mit curl?

Der einfachste Test ist eine reine Kopfzeilen-Abfrage:

curl -sI https://www.example.de/ | grep -iE 'strict-transport|content-security|x-content-type|referrer-policy|permissions-policy|x-frame|server|x-powered'

Beachten Sie: -I sendet eine HEAD-Anfrage. Manche Anwendungen antworten darauf anders als auf GET. Wollen Sie das Verhalten für echte Besucher sehen, nutzen Sie curl -s -D - -o /dev/null https://www.example.de/, das die Header einer GET-Antwort ausgibt. Testen Sie außerdem nicht nur die Startseite: Fehlerseiten (/gibt-es-nicht), statische Dateien (/assets/app.css) und der Login-Bereich werden häufig von anderen Konfigurationsblöcken bedient und zeigen dann andere Header.

Beispiel: Auswertung einer Antwort

Ein Test liefert Server: nginx/1.24.0, X-Powered-By: PHP/8.2.12, aber weder HSTS noch nosniff. Bewertung: Zwei Informationslecks (Versionen) und zwei fehlende Schutzheader. Maßnahmen in sinnvoller Reihenfolge: (1) nosniff setzen (praktisch risikofrei), (2) Versionen verbergen, (3) HSTS stufenweise einführen, (4) Referrer-Policy ergänzen, (5) CSP im Report-Only-Modus starten. Danach wiederholen Sie den Test auch gegen eine Fehlerseite und eine statische Datei.

Welche typischen Fehler passieren?

FehlerFolgeGegenmaßnahme
HSTS mit includeSubDomains ohne Inventur der SubdomainsAlte oder interne Subdomains werden unerreichbarZuerst alle Subdomains auflisten, HTTPS sicherstellen, stufenweise erhöhen
CSP sofort scharf mit 'unsafe-inline' als „Notlösung“Trügerische Sicherheit, XSS-Schutz fehlt weitgehendReport-Only, dann Nonces oder Hashes statt 'unsafe-inline'
nginx add_header ohne alwaysHeader fehlen bei Fehlerseitenalways setzen
Header im server-Block, eigener add_header in locationSecurity-Header verschwinden für diese PfadeHeader in der Location wiederholen oder per include
Doppelte Header (Server und CDN setzen beide)Widersprüchliche oder doppelt gesendete WerteAn einer Stelle setzen, Gegenstelle abschalten
Nur Startseite getestetLogin, Fehlerseiten und Assets bleiben ungeschütztMehrere Pfade prüfen
HSTS über HTTP erwartetWirkt nicht, wird ignoriertHeader nur in der HTTPS-Konfiguration senden
Veraltete Header als „Sicherheit“ gesetztKein Nutzen, zusätzlicher PflegeaufwandAuf aktuelle Header konzentrieren

Checkliste: Security-Header prüfen

  1. Wird die Seite ausschließlich über HTTPS ausgeliefert und leitet HTTP korrekt um (siehe Weiterleitungen und Redirect-Ketten)?
  2. Ist Strict-Transport-Security gesetzt, zunächst mit kurzer, dann mit langer Laufzeit?
  3. Gibt es X-Content-Type-Options: nosniff?
  4. Ist eine Referrer-Policy definiert?
  5. Läuft eine CSP, mindestens im Report-Only-Modus, ohne 'unsafe-eval'?
  6. Ist Einbettung in fremde Seiten über frame-ancestors oder X-Frame-Options geregelt?
  7. Sind Server-Versionen und X-Powered-By entfernt?
  8. Stimmen die Header auch bei Fehlerseiten, statischen Dateien und im Login-Bereich?
  9. Wird nach jedem Deployment, Hosterwechsel oder CDN-Wechsel erneut geprüft?

Grenzen und Einordnung

Security-Header sind kein Sicherheitskonzept. Sie ändern nichts an unsicheren Passwörtern, ungepatchter Software oder fehlerhafter Eingabeprüfung. Sie wirken zudem nur im Browser: Ein Angreifer, der direkt mit Skripten Ihre Schnittstellen abfragt, ignoriert sie. Und eine Prüfung von außen sieht nur, was der Server sendet. Sie kann nicht beurteilen, ob eine CSP sinnvoll ist, also ob script-src tatsächlich nur das Nötige erlaubt. Dafür braucht es Sachverstand und Tests im Browser.

Auch Bewertungsnoten externer Header-Tests sollten Sie nicht mit Sicherheit gleichsetzen: Eine Seite mit „Bestnote“ kann dennoch verwundbar sein, und eine Seite mit mittlerer Note kann gut abgesichert sein, wenn sie bewusst auf einen Header verzichtet. Entscheidend ist, dass Sie jeden fehlenden Header begründen können. Die Aufnahme in einen Prüfbericht ist ein Anlass zum Hinsehen, kein Urteil.

Wie setzen Sie die Prüfung mit UPTIMESHIELD um?

Der Sofort-Report prüft ohne Konto eine URL und wertet unter anderem die Security-Header aus; das Ergebnis fließt in den Teil „Sicherheit“ des Scores ein und erscheint mit konkreten Hinweisen in der Maßnahmenliste. Wiederkehrend nutzen Sie die Website-Checks im Dashboard: Sie prüfen SEO, Sicherheit, Technik und DNS in Abständen erneut und zeigen den Notenverlauf sowie, was seit der letzten Prüfung neu hinzukam oder behoben wurde. So fällt auf, wenn nach einem Deployment Header verschwinden. Das Zertifikat selbst überwacht der Monitortyp SSL-Zertifikat (Ablaufwarnungen 30, 14, 7, 3 und 1 Tag vorher); Hintergründe dazu in SSL-Zertifikate rechtzeitig prüfen. Wie weit automatische Prüfungen reichen, beschreibt Grenzen automatischer Website-Prüfungen. Das Dashboard und die Website-Checks erreichen Sie nach der kostenlosen Registrierung.

Quellen und weiterführende Standards

Externe Links führen zu den Original-Spezifikationen und offiziellen Dokumentationen. Die Einordnung und die Beispielrechnungen stammen aus der Messmethodik von UPTIMESHIELD.

Selbst prüfen: Testen Sie jetzt, ob Ihre Website erreichbar ist und wie schnell sie antwortet – mit dem Uptime Checker.

Häufige Fragen zum Thema

Welche Security-Header sollte jede Website mindestens setzen?
Als Mindestausstattung gelten Strict-Transport-Security (HSTS), X-Content-Type-Options: nosniff und eine Referrer-Policy; eine Content-Security-Policy und eine Permissions-Policy kommen hinzu, sobald Sie sie testen können. Auch die Einbettung in fremde Seiten sollten Sie bewusst regeln.
Wie prüfe ich meine Security-Header?
Mit curl -sI https://ihre-domain.de/ sehen Sie alle Antwort-Header. Prüfen Sie zusätzlich Fehlerseiten und statische Dateien. Automatisch geht es mit dem Sofort-Report oder einem wiederkehrenden Website-Check.
Kann HSTS meine Website kaputt machen?
Ja, wenn Subdomains ohne gültiges HTTPS existieren und includeSubDomains gesetzt ist, oder wenn Sie HSTS mit sehr langer Laufzeit aktivieren und später doch auf HTTP zurück müssen. Führen Sie HSTS deshalb stufenweise mit steigendem max-age ein.
Was ist der Unterschied zwischen CSP und Report-Only?
Die normale Content-Security-Policy blockiert Verstöße. Die Report-Only-Variante meldet sie nur, ohne etwas zu blockieren, und eignet sich, um eine Policy gefahrlos zu testen.
Brauche ich X-XSS-Protection?
Nein. Der Filter ist in modernen Browsern entfernt oder deaktiviert. Verlassen Sie sich auf eine Content-Security-Policy; setzen Sie den Header, falls überhaupt, mit dem Wert 0.
Warum fehlen meine Header in nginx bei bestimmten Seiten?
Meist wegen der Vererbung: Sobald ein location-Block ein eigenes add_header enthält, werden die Header aus dem server-Block für diesen Block nicht mehr übernommen. Wiederholen Sie die Security-Header dort oder binden Sie sie per include ein.