Security-Header in nginx und Apache richtig setzen

Ein paar Zeilen in der Serverkonfiguration schützen vor Clickjacking, MIME-Sniffing und vielen Folgen von XSS. Wichtig ist, sie so zu setzen, dass sie auch wirklich bei jeder Antwort ankommen.

Welche Header sinnvoll sind

Nicht mehr nötig ist X-XSS-Protection. Moderne Browser ignorieren ihn, in alten konnte er sogar schaden.

nginx

# /etc/nginx/snippets/security-headers.conf
add_header Strict-Transport-Security "max-age=63072000; 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 "default-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'" always;

# im server-Block:
include snippets/security-headers.conf;
server_tokens off;

Zwei Fallen gibt es bei nginx:

Apache

# sudo a2enmod headers
<VirtualHost *:443>
    Header always set Strict-Transport-Security "max-age=63072000; 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 "default-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'"
    Header always unset X-Powered-By
</VirtualHost>

# global, z. B. in security.conf
ServerTokens Prod
ServerSignature Off

Auf Webhosting ohne Zugriff auf die Serverkonfiguration funktionieren dieselben Header-Zeilen meist auch in der .htaccess im Hauptverzeichnis. Die PHP-Version im Header X-Powered-By schaltest du mit expose_php = Off in der php.ini ab.

Die CSP einführen, ohne die Seite kaputt zu machen

Eine zu strenge CSP blockiert eigene Skripte, eingebettete Videos oder Analyse-Tools. Deshalb in Stufen vorgehen:

  1. Zuerst als Content-Security-Policy-Report-Only setzen. Der Browser blockiert nichts, meldet Verstöße aber in der Konsole.
  2. Die Konsole auf den wichtigsten Seiten durchgehen und benötigte Quellen ergänzen, z. B. script-src 'self' https://cdn.example.net.
  3. Inline-Skripte in Dateien auslagern oder mit einer Nonce versehen. 'unsafe-inline' bei script-src hebelt den XSS-Schutz weitgehend aus.
  4. Erst dann auf Content-Security-Policy umstellen.

Vorsicht bei HSTS

HSTS lässt sich nicht einfach zurücknehmen: Browser merken sich die Vorgabe für die angegebene Zeit. Fang mit max-age=300 an, prüfe, ob wirklich alle Subdomains HTTPS können, und erhöhe dann auf zwei Jahre. includeSubDomains betrifft auch interne Namen wie intranet.example.com, wenn sie unter derselben Domain liegen.

Prüfen

curl -sI https://example.com
curl -sI https://example.com/gibt-es-nicht   # auch bei 404?

Der Security-Header-Check bewertet alle Header, erkennt typische Fehler wie 'unsafe-inline' und erzeugt die passenden Zeilen für deinen Server.

FAQ

Reicht X-Frame-Options oder brauche ich frame-ancestors?

frame-ancestors in der CSP ist der moderne Weg und erlaubt auch mehrere Quellen. Für sehr alte Browser schadet X-Frame-Options: SAMEORIGIN zusätzlich nicht.

Warum sehe ich die Header doppelt?

Meist setzen sie sowohl die Anwendung (z. B. PHP oder ein CMS) als auch der Webserver. Doppelte CSP-Header werden beide angewendet, die strengere gewinnt. Am besten nur an einer Stelle setzen.

Gehören Security-Header auch auf APIs?

Ja, zumindest HSTS, nosniff und eine knappe CSP wie default-src 'none'; frame-ancestors 'none'. Sie kosten nichts und verhindern, dass Antworten im Browser missbraucht werden.

Setzt ein CDN die Header für mich?

Nur wenn du es dort einrichtest. Viele CDNs reichen die Header des Ursprungs-Servers einfach durch.