Zur Suche springen Zur Navigation springen Zum Hauptinhalt springen Zum Footer springen

Website-Sicherheit mit HTTP Security-Header erhöhen

Mit Hilfe von HTTP Security-Headern lässt sich die Sicherheit einer Website deutlich verbessern. Es gibt verschiedene HTTP Security-Header, die wir hier im Einzelnen erklären wollen. Einige dieser Header sind sehr einfach in eine Website einzubinden, andere sind komplexer und benötigen etwas mehr Konfigurationsarbeit. Wir zeigen, wie man für Websites die HTTP Security-Header aktiviert und konfiguriert. Dabei gehen wir unter anderem auf die Integration der Header in WordPress ein, beschreiben aber auch den Weg ohne WordPress.

Was sind HTTP Security-Header?

Fordert ein Browser eine Seite von einem Webserver an, dann antwortet der Webserver mit der Auslieferung der Seite und sendet außerdem einen HTTP-Response-Header mit dem Inhalt.
Neben Metadaten wie Zeichensätzen und Fehlercodes können auch sicherheitsrelevante Einstellungen gesendet werden. Diese schreiben dem Browser vor, wie er sich zu verhalten hat. Sicherheit ist leider ein gern vernachlässigtes Thema bei vielen Website-Betreibern. Man sollte sich unbedingt mit dieser Thematik beschäftigen, wenn man nicht Opfer einer Hacker-Attacke werden möchte. Über die HTTP Security-Header kann man dies oftmals recht einfach umsetzen.

Welche Header gibt es und was können sie?

X-Frame-Options (XFO)

Dieser Header verhindert, dass die Seite in einen Frame in einer anderen Seite geladen werden kann. Nicht unbedingt für die eigene Sicherheit, aber was Content-Diebstahl, Missbrauch etc. betrifft, sicher sehr hilfreich. Mit dem Wert »deny« wird keinerlei Laden in einem Frame zugelassen, mit »sameorigin« nur »in sich selbst«.

X-Frame-Options: DENY

X-Content-Type-Options

Dem Browser wird normalerweise mitgeteilt, welche Dateiformate er jeweils laden soll, also z. B. HTML oder JPG. Wenn das nicht angegeben wird, soll der Browser »raten«. Das kann man ausnutzen und so andere Formate einschleusen, die Schaden anrichten können. Mit dem Setzen dieses Headers untersagt man dem Browser das »sniffen« und unterbindet diese Angriffsmöglichkeit.

X-Content-Type-Options: nosniff

HTTP Strict-Transport-Security (HSTS)

Dieser Header informiert den Browser, dass die Seite nur per HTTPS aufgerufen werden darf. Voraussetzung ist hierbei natürlich, dass die Seite über ein SSL-Zertifikat verfügt.

Über den Parameter »max-age« wird die Zeit (in Sekunden) angegeben, in der der Browser sich merken soll, das die Seite nur über HTTPS aufgerufen werden darf. Mit »includeSubdomains« werden alle Subdomains mit in diese Regel eingeschlossen.

Strict-Transport-Security: max-age=<expire-time>; includeSubdomains

Referrer-Policy

Dieser Header steuert, ob der Referrer-Wert bei ausgehenden Links übergeben werden darf. Das heißt, darf der Browser einer Seite mitteilen, von welcher Seite der Benutzer gekommen ist. Mit dem Wert »no-referrer« verbietet man das komplett.

Dieser Header ist nicht direkt für die »Sicherheit« der Website verantwortlich aber in Bezug auf den Datenschutz schon interessant.

Referrer-Policy: no-referrer

Permissions-Policy

Der Permissions-Policy-Header hieß früher »Feature-Policy« und wurde im Mai 2020 umbenannt. Auch die Syntax für die Header-Werte hat sich geändert.

Dieser Header hat nicht so sehr die Sicherheit der Website oder der Betreiber im Mittelpunkt, sondern vielmehr die Datensicherheit des Besuchers. In heutigen Zeiten ein Feature, das man nicht hoch genug einschätzen kann. Man kann den Einsatz von Mikrofon oder Kamera, den Abruf des Standorts, die Nutzung der Vibrationsfunktion u. a. unterbinden oder zulassen.

Permissions-Policy: <directive>=(<allowlist>), <directive>=(<allowlist>)

Content-Security-Policy (CSP)

Dieser Security-Header umfasst viele Konfigurationsmöglichkeiten. Mit der Content-Security-Policy kann man detailliert festlegen, welche Inhaltstypen überhaupt ausgeliefert werden dürfen und von welchen Quellen. Das macht ihn so mächtig, dass man beim Setzen der Parameter sehr aufpassen sollte. Hier ist es ausschlaggebend, welche konkreten Rahmenbedingungen für eine Website gelten.

Soll die Website beispielsweise nur eigene Scripte und Scripte von Google erlauben, muss man dem Parameter »script-src« die Werte »self« und »https://www.google.com« zuweisen. Nach diesem Muster ordnet man allen weiteren Parametern ebenfalls die Werte zu. Eine Liste aller Parameter findet ihr hier.

Content-Security-Policy: default-src 'self'; script-src 'self' https://www.google.com; img-src 'self'; style-src 'self'; font-src 'self'; object-src 'none'; frame-src 'self'; worker-src 'self'; connect-src 'self';

X-XSS-Protection

Dieser Header verhindert das bekannte »Cross Site Scripting«, das gefürchtete Laden von fremden Scripten in die Website. Damit wird ggf. bösartiges JavaScript im Browser ausgeführt, ohne dass der Benutzer es überhaupt mitbekommt. Allerdings verursachte der Eintrag Sicherheits- und Datenschutz-Probleme, weshalb er von aktuellen Browsern gar nicht mehr unterstütz wird. Der Eintrag sollte daher auf „0“ gesetzt oder gleich ganz entfernt werden. Mit einer sauber eingerichteten Content Security Policy ist der X-XSS-Protection Header ohnehin überflüssig.

Security Report erhalten

Durch den Einsatz des Content-Security-Policy Headers erstellt man eine Whitelist für alle erlaubten Quellen. Da dies sehr komplex ist, kann es durchaus passieren, dass man anfänglich nicht alle Quellen erfasst hat. Hierbei ist es hilfreich, einen »Security Report« einzurichten, der Informationen über geblockte Inhalte erfasst und in ein Log-File schreibt. Zusätzlich besteht die Möglichkeit, diese Informationen auch via E-Mail zu versenden, sobald ein »Problem« auftritt.

Content-Security-Policy: report-uri /security-report.php

Zum Erstellen dieses Security-Reports muss folgender Code in eine PHP-Datei übernommen werden und im Verzeichnis eurer Website abgelegt werden. Der Pfad zur Datei wird dann als Endpunkt hinter dem Parameter »report-uri« an den Content-Security-Policy Header angehangen.

<?php
$log_file = dirname(__FILE__) . '/csp-violations.log';
$log_file_size_limit = 1000000; // bytes
$email_address = 'email@domain.dlt';
$email_subject = 'Content-Security-Policy violation';

$current_domain = preg_replace('/www./i', '', $_SERVER['SERVER_NAME']);
$email_subject = $email_subject . ' on ' . $current_domain;
http_response_code(204); // HTTP 204 No Content

$json_data = file_get_contents('php://input');
if ($json_data = json_decode($json_data)) {
  $json_data = json_encode($json_data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);

  if (!file_exists($log_file)) {
    // Send an email
    $message = "The following Content-Security-Policy violation occurred on " .
    $current_domain . ":nn" .
    $json_data .
    "nnFurther CSP violations will be logged to the following log file, but no further email notifications will be sent until this log file is deleted:nn" .
    $log_file;
    mail($email_address, $email_subject, $message,
         'Content-Type: text/plain;charset=utf-8');
  } else if (filesize($log_file) > $log_file_size_limit) {
    exit(0);
  }
  file_put_contents($log_file, $json_data, FILE_APPEND | LOCK_EX);
}
?>

Integration der HTTP Security Header über die .htaccess

Die Integration der Security Header wird standardmäßig über die .htaccess durchgeführt. Das folgende Snippet ist ein Beispiel für diese Integration.

<IfModule mod_headers.c>
  Header always set X-Frame-Options "deny"
  Header always set X-Content-Type-Options "nosniff"
  Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
  Header always set Referrer-Policy "no-referrer"
  Header always set Permissions-Policy "accelerometer=()‚ autoplay=(self), camera=(), encrypted-media=(), fullscreen=(), geolocation=(self), gyroscope=(), magnetometer=(), microphone=(), midi=(), payment=(), picture-in-picture=(self), usb=()"
  Header always set Content-Security-Policy "default-src 'self'; script-src 'self' https://matomo.org; img-src 'self'; style-src 'self'; font-src 'self'; object-src 'none'; frame-src 'self'; worker-src 'self'; connect-src 'self'; report-uri /security-report.php"
</IfModule>

Integration der HTTP Security Header über WordPress-Hook

Wenn es sich bei der Website um eine WordPress-Umsetzung handelt, können die Security Header mit dem Filter »wp_headers« über die functions.php integriert werden.

if (!empty($_SERVER['HTTPS'])) {
  function kb_add_security_headers($headers) {
    $headers["x-frame-options"] = "deny";
    $headers["x-content-type-options"] = "nosniff";
    $headers["strict-transport-security"] = "max-age=31536000; includeSubDomains";
    $headers["referrer-policy"] = "no-referrer";
    $headers["permissions-policy"] = "accelerometer=(), autoplay=(self), camera=(), encrypted-media=(), fullscreen=(), geolocation=(self), gyroscope=(), magnetometer=(), microphone=(), midi=(), payment=(), picture-in-picture=(self), usb=()";
    $headers["content-security-policy"] = "default-src 'self'; script-src 'self' https://matomo.org; img-src 'self'; style-src 'self'; font-src 'self'; object-src 'none'; frame-src 'self'; worker-src 'self'; connect-src 'self'; report-uri ".esc_url(get_template_directory_uri())."/security-report.php";
    return $headers;
  }
  add_filter('wp_headers', 'kb_add_security_headers');
}

Testen der HTTP Security Header

Nach der Integration empfiehlt es sich, die Header auf ihre Funktionsfähigkeit zu testen. Hierfür gibt es einige Tools im Internet.

Geschrieben von kulturbanause Team

Benutzerbild

Beiträge bei denen das kulturbanause-Team als Autor angegeben ist, wurden von mehreren Personen in Zusammenarbeit geschrieben. Wir nutzen diesen Blog als öffentliches Archiv und um euch bei alltäglichen Problemen im Zusammenhang mit der Erstellung von Websites zu helfen. Neben diesem Blog bieten wir auch Trainings wie Schulungen, Bücher oder Videos an. Und natürlich unterstützen wir auch gerne im Rahmen unserer Agenturtätigkeit.

Feedback & Ergänzungen – 12 Kommentare

  1. Daniel Ruf
    schrieb am 07.09.2023 um 17:02 Uhr:

    X-XSS-Protection sollte nicht mehr genutzt werden, wurde auch bereits in einigen Browsern entfernt. Das schützte nur kaum, war leicht zu umgehen und verursachte neue Sicherheits- und Datenschutz-Probleme.

    https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-XSS-Protection

    https://caniuse.com/mdn-http_headers_x-xss-protection

    Bei „Header set …“ würde ich in der Regel „Header always set …“ empfehlen, damit das auch bei anderen Statuscodes als 200 gesetzt wird (bzw. bei Fehlercodes wie 500, 40x, …).

    Antworten
    • Konstantin Hanke
      schrieb am 18.09.2023 um 09:17 Uhr:

      Hallo Daniel, vielen Dank für den wertvollen Hinweis! Wir haben den Artikel entsprechend angepasst.

      Antworten
  2. Tim
    schrieb am 14.04.2022 um 10:06 Uhr:

    Ich denke Google hat das ganze FloC Experiment eingestampft:
    https://www.heise.de/news/Cookie-Nachfolge-Google-beerdigt-FLoC-6337936.html

    Hier sollte man vll. den entsprechenden Header wieder raus nehmen…

    Antworten
    • Konstantin Hanke
      schrieb am 18.09.2023 um 09:19 Uhr:

      Hallo Tim, besten Dank für den Hinweis! Wir haben den Eintrag aktualisiert.

      Antworten
  3. SGRF
    schrieb am 30.05.2021 um 05:20 Uhr:

    Hallo und Danke schön!
    Endlich eine aktuelle, leicht verständliche, kurze deutsche Zusammenfassung zu diesem Thema auch für weniger Erfahrene.
    HTTP Security Header sind natürlich etwas feines für HTTP und HTTPS.
    Nur wie verhält es sich, wenn eine Website auch einmal anderes, z.B. JSON oder XMLNS Daten ausliefert?
    Derzeit klotze ich die Security Header in alle Antworten, vom ‚Authorization Required‘ über HTTP(S), SVG-Bildern bis natürlich JSON und XML(NS).

    Antworten
  4. Heike Lorenz
    schrieb am 22.12.2020 um 15:27 Uhr:

    Hi Jonas,
    Danke für diese Anleitung!

    Ich hab lange gesucht zu dem Thema eine deutsche Anleitung zu finden, denn Englisch & Nerd-Begriffe – da steige ich bei diesem komplexen Thema leider aus.

    Mit deiner Hilfe trau mich jetzt endlich mal an das Thema ran, nur vor der „Permissions-Policy“ und der „Content-Security-Policy (CSP)“ hab ich echt noch Respekt, da muss ich erstmal rausfinden, was auf meiner Seite eigentlich alles so geladen wird bzw. läuft…
    Kennst Du ein einfaches Tool für die Analyse? Das in Chrome eingebaute hilft mir leider nicht so wirklich, ich verstehe oft einfach nicht, was es mir sagen will.

    Danke auf jeden Fall für den Anschub, zwischen den Jahren hab ich damit jetzt was zu basteln :-)

    Lieben Gruß & Frohe Weihnachten
    Heike

    Antworten
    • Jonas Hellwig
      schrieb am 22.12.2020 um 15:36 Uhr:

      Hallo Heike, vielen Dank für dein Feedback. Ich habe selbst allerdings tatsächlich recht wenig Anteil an diesem Team-Artikel. Ich gebe das Lob aber gerne an meinen Kollegen Robert weiter :) Wie im Abschnitt »Security Report erhalten« beschrieben, kannst du es so konfigurieren, dass du eine Mail erhältst, sobald etwas erstmalig geblockt wird. So merkst du recht schnell, wenn etwas vergessen wurde. Einen Scanner o.ä. kenne ich nicht.

      Antworten
      • Heike Lorenz
        schrieb am 22.12.2020 um 16:52 Uhr:

        Hi Jonas,
        das ging jetzt fix :-)

        Ich hab mir für die ersten Versuche jetzt lieber mal ein Plugin (https://wordpress.org/plugins/http-headers/) installiert – da kann ich das einfacher steuern und muss nicht selbst im Code rumwühlen. Im Plugin ist zumindest eine Testfunktion enthalten was die Content-Security-Policy (CSP) angeht und man kann Stück für Stück schauen, was für Fehler ausgegeben werden.

        Sobald ich mich sicherer fühle, werde ich den Code (inkl. der Mailfunktion) dann direkt in die htaccess einbauen…

        Viele Grüße
        Heike

  5. Frank
    schrieb am 25.07.2020 um 12:29 Uhr:

    Ganz herzlichen Dank, dass Du Dein Wissen großzügig und vor allem immer verständlich aufbereitet hier teilst. Seit ich zwei kleine Firmen-Websites betreue, bin ich dankbar für jeden Hinweis zur Verbesserung der Sicherheit.

    Beim Ausprobieren des WordPress-Codes ist mir aufgefallen, dass wohl noch ein kleiner Tippfehler enthalten ist? In der Zeile
    $headers[„content-security-policy“] = „“default-src
    ist hinter dem Gleichheitszeichen ein Anführungszeichen zuviel.

    Antworten
  6. Torben Andresen
    schrieb am 21.07.2020 um 15:54 Uhr:

    Moin,

    vielen Dank für einen weiteren tollen Beitrag.

    Diesmal ist mir aber ein kleiner Schreibfehler aufgefallen und zwar im report-uri Script. Im Teil für den E-Mailtext steht: „Further CPS violations“, das müsste aber CSP heißen. Zugegeben, ist wirklich nur eine Winzigkeit. ;)

    Antworten
    • Jonas Hellwig
      schrieb am 21.07.2020 um 18:10 Uhr:

      Vielen Dank – wir haben den Typo korrigiert.

      Antworten
    • Jonas Hellwig
      schrieb am 27.07.2020 um 15:47 Uhr:

      Hallo Torben, Danke für den Hinweis! Ist geändert.

      Antworten

Kommentar zu dieser Seite

Wir freuen uns über Anregungen, Ergänzungen oder Hinweise zu Fehlern. Wir lesen jeden Eintrag, veröffentlichen aber nur, was den Inhalt sinnvoll ergänzt.

WordPress-Projekte mit kulturbanause

Wir wissen wovon wir reden. Wir setzen WordPress seit über 10 Jahren erfolgreich ein und realisieren maßgeschneiderte Websites auf Basis dieses großartigen CMS.

WordPress-Leistungsangebot →

Schulungen von kulturbanause

Wir bieten Seminare und Workshops zu den Themen Konzept, Design und Development. Immer up-to-date, praxisnah, kurzweilig und mit dem notwendigen Blick über den Tellerrand.

Übersicht Schulungsthemen →