Content Security Policy (CSP)

Content Security Policy (CSP) ist eine Funktion, die hilft, das Risiko bestimmter Sicherheitsbedrohungen zu verhindern oder zu minimieren. Sie besteht aus einer Reihe von Anweisungen einer Website an einen Browser, die den Browser anweisen, Einschränkungen für die Aktivitäten des die Site bildenden Codes zu setzen.

Der primäre Anwendungsfall für CSP ist die Kontrolle, welche Ressourcen, insbesondere JavaScript-Ressourcen, ein Dokument laden darf. Dies wird hauptsächlich als Verteidigung gegen Cross-Site Scripting (XSS)-Angriffe verwendet, bei denen ein Angreifer bösartigen Code in die Seite des Opfers einschleusen kann.

Ein weiterer Zweck von CSP kann die Verteidigung gegen Clickjacking sein und die Sicherstellung, dass die Seiten einer Site über HTTPS geladen werden.

In diesem Leitfaden beginnen wir mit einer Beschreibung, wie eine CSP an einen Browser geliefert wird und wie sie auf hoher Ebene aussieht.

Dann beschreiben wir, wie sie verwendet werden kann, um zu kontrollieren, welche Ressourcen geladen werden, um XSS zu verhindern, sowie andere Anwendungsfälle wie Clickjacking-Schutz und Aufrüsten unsicherer Anfragen. Beachten Sie, dass es keine Abhängigkeiten zwischen den verschiedenen Anwendungsfällen gibt: Wenn Sie Clickjacking-Schutz hinzufügen möchten, aber keine XSS-Minderung, können Sie einfach die Direktiven für diesen Anwendungsfall hinzufügen.

Schließlich beschreiben wir Strategien zur Bereitstellung einer CSP und Werkzeuge, die diesen Prozess erleichtern können.

CSP-Übersicht

Eine CSP sollte an den Browser im Content-Security-Policy Antwort-Header geliefert werden. Sie sollte für alle Antworten auf alle Anfragen gesetzt werden, nicht nur für das Hauptdokument.

Sie können sie auch mit dem Attribut http-equiv des <meta> Elements Ihres Dokuments angeben, was eine nützliche Option für einige Anwendungsfälle ist, z. B. eine client-seitig gerenderte Single Page App, die nur statische Ressourcen hat, weil Sie dann nicht auf eine Serverinfrastruktur angewiesen sind. Diese Option unterstützt jedoch nicht alle CSP-Funktionen.

Die Richtlinie wird als eine Reihe von Direktiven angegeben, die durch Semikolons getrennt sind. Jede Direktive steuert einen anderen Aspekt der Sicherheitsrichtlinie. Jede Direktive hat einen Namen, gefolgt von einem Leerzeichen, gefolgt von einem Wert. Unterschiedliche Direktiven können unterschiedliche Syntaxen haben.

Betrachten Sie zum Beispiel die folgende CSP:

http
Content-Security-Policy: default-src 'self'; img-src 'self' example.com

Sie setzt zwei Direktiven:

  • Die default-src Direktive ist auf 'self' gesetzt
  • Die img-src Direktive ist auf 'self' example.com gesetzt.

Eine CSP, aufgeschlüsselt in ihre Direktiven.

Die erste Direktive, default-src, weist den Browser an, nur Ressourcen zu laden, die sich im gleichen Ursprung wie das Dokument befinden, es sei denn, andere spezifischere Direktiven setzen eine andere Richtlinie für andere Ressourcentypen. Die zweite, img-src, weist den Browser an, Bilder zu laden, die entweder gleichen Ursprung haben oder von example.com stammen.

Im nächsten Abschnitt betrachten wir die verfügbaren Werkzeuge zur Kontrolle von Ressourcennachladen, welches die Hauptfunktion einer CSP ist.

Kontrolle des Ressourcennachladens

Eine CSP kann verwendet werden, um die Ressourcen zu kontrollieren, die ein Dokument laden darf. Dies wird hauptsächlich zum Schutz vor Cross-Site Scripting (XSS)-Angriffen verwendet.

In diesem Abschnitt sehen wir zuerst, wie die Kontrolle von Ressourcennachladen helfen kann, XSS zu verhindern, dann die Werkzeuge, die CSP bereitstellt, um zu kontrollieren, welche Ressourcen geladen werden. Schließlich beschreiben wir eine besonders empfohlene Strategie, die "Strict CSP" genannt wird.

XSS und Ressourcennachladen

Ein Cross-Site Scripting (XSS)-Angriff ist ein Angriff, bei dem ein Angreifer seinen Code im Kontext der Zielwebsite ausführen kann. Dieser Code kann dann alles tun, was der Code der Website selbst tun könnte, einschließlich z. B.:

  • Zugreifen auf oder Modifizieren des Inhalts der geladenen Seiten der Website
  • Zugreifen auf oder Modifizieren des Inhalts im lokalen Speicher
  • HTTP-Anfragen mit den Anmeldedaten des Benutzers durchführen, wodurch es möglich wird, den Benutzer zu imitieren oder auf sensible Daten zuzugreifen

Ein XSS-Angriff ist möglich, wenn eine Website eine Eingabe akzeptiert, die von einem Angreifer erstellt worden sein könnte (z. B. URL-Parameter oder ein Kommentar zu einem Blogpost), und diese dann in die Seite einschließt, ohne sie zu sanitizeren: das heißt, ohne sicherzustellen, dass sie nicht als JavaScript ausgeführt werden kann.

Websites sollten sich vor XSS schützen, indem sie diese Eingabe sanitiseren, bevor sie sie in die Seite einfügen. Eine CSP bietet einen ergänzenden Schutz, der die Website schützen kann, selbst wenn die Sanitization fehlschlägt.

Wenn die Sanitization fehlschlägt, gibt es verschiedene Formen, die der eingeschleuste bösartige Code im Dokument annehmen kann, einschließlich:

  • Ein <script> Tag, das auf eine bösartige Quelle verweist:

    html
    <script src="https://evil.example.com/hacker.js"></script>
    
  • Ein <script> Tag, das Inline-JavaScript enthält:

    html
    <script>
      console.log("You've been hacked!");
    </script>
    
  • Ein Inline-Ereignishandler:

    html
    <img onmouseover="console.log(`You've been hacked!`)" />
    
  • Eine javascript: URL:

    html
    <iframe src="javascript:console.log(`You've been hacked!`)"></iframe>
    
  • Ein String-Argument für eine unsichere API wie eval():

    js
    eval("console.log(`You've been hacked!`)");
    

Eine CSP kann gegen all dies Schutz bieten. Mit einer CSP können Sie:

  • die erlaubten Quellen für JavaScript-Dateien und andere Ressourcen definieren und dadurch das Laden von https://evil.example.com effektiv blockieren
  • Inline-Skripttags deaktivieren
  • nur Skripttags zulassen, die das korrekte nonce oder den korrekten hash haben
  • Inline-Ereignishandler deaktivieren
  • javascript: URLs deaktivieren
  • gefährliche APIs wie eval() deaktivieren

Im nächsten Abschnitt gehen wir auf die von CSP bereitgestellten Werkzeuge ein, um diese Dinge zu tun.

Hinweis: Das Setzen einer CSP ist keine Alternative zur Sanitisierung von Eingaben. Websites sollten Eingaben sanitizeren und eine CSP setzen, um einen tiefgehenden Schutz gegen XSS zu bieten.

Abrufdirektiven

Abrufdirektiven werden verwendet, um eine bestimmte Ressourcenkategorie anzugeben, die ein Dokument laden darf - z. B. JavaScript, CSS-Stylesheets, Bilder, Schriftarten usw.

Es gibt unterschiedliche Abrufdirektiven für unterschiedliche Arten von Ressourcen. Zum Beispiel:

  • script-src legt erlaubte Quellen für JavaScript fest.
  • style-src legt erlaubte Quellen für CSS-Stylesheets fest.
  • img-src legt erlaubte Quellen für Bilder fest.

Eine spezielle Abrufdirektive ist default-src, die eine Fallback-Richtlinie für alle Ressourcen festlegt, deren Direktiven nicht explizit aufgelistet sind.

Für die vollständige Liste der Abrufdirektiven siehe die Referenzdokumentation.

Jede Abrufdirektive wird entweder als das Einzelstichwort 'none' oder als ein oder mehrere Quellausdrücke angegeben, die durch Leerzeichen getrennt sind. Wenn mehr als ein Quellausdruck aufgelistet ist: Wenn eine der Methoden die Ressource zulässt, dann ist die Ressource erlaubt.

Zum Beispiel legt die folgende CSP zwei Abrufdirektiven fest:

  • default-src erhält den Einzelquellausdruck 'self'
  • img-src erhält zwei Quellausdrücke: 'self' und example.com

CSP-Diagramm, das Quellausdrücke zeigt

Die Wirkung davon ist:

  • Bilder müssen entweder den gleichen Ursprung haben wie das Dokument oder von example.com geladen werden.
  • Alle anderen Ressourcen müssen den gleichen Ursprung haben wie das Dokument.

In den nächsten Abschnitten beschreiben wir einige der Möglichkeiten, wie Sie Quellausdrücke verwenden können, um Ressourcennachladen zu kontrollieren. Beachten Sie, dass, obwohl wir sie separat beschreiben, diese Ausdrücke im Allgemeinen kombiniert werden können: Eine einzelne Abrufdirektive kann zum Beispiel Nonces sowie Hostnamen beinhalten.

Blockieren von Ressourcen

Um einen Ressourcentyp vollständig zu blockieren, verwenden Sie das Stichwort 'none'. Zum Beispiel blockiert die folgende Direktive alle <object> und <embed> Ressourcen:

http
Content-Security-Policy: object-src 'none'

Beachten Sie, dass 'none' nicht mit einer anderen Methode in einer bestimmten Direktive kombiniert werden kann: Tatsächlich werden alle anderen Quellausdrücke, die neben 'none' angegeben sind, ignoriert.

Nonces

Ein nonce ist der empfohlene Ansatz, um das Laden von <script> und <style> Ressourcen zu beschränken.

Bei einem nonce generiert der Server einen zufälligen Wert für jede HTTP-Antwort und fügt ihn in eine script-src und/oder eine style-src Direktive ein:

http
Content-Security-Policy:
  script-src 'nonce-416d1177-4d12-4e3b-b7c9-f6c409789fb8'

Der Server fügt diesen Wert dann als Wert des nonce Attributs aller <script> und/oder <style> Tags ein, die sie in das Dokument einfügen möchten.

Der Browser vergleicht die beiden Werte und lädt die Ressource nur, wenn sie übereinstimmen. Die Idee ist, dass selbst wenn ein Angreifer es schafft, JavaScript in die Seite einzufügen, er nicht wissen wird, welches nonce der Server verwenden wird, sodass der Browser das Skript ablehnt.

Damit dieser Ansatz funktioniert, muss es für einen Angreifer unmöglich sein, das nonce zu erraten.

In der Praxis bedeutet dies, dass das nonce für jede HTTP-Antwort unterschiedlich und nicht vorhersehbar sein muss.

Dies bedeutet wiederum, dass der Server kein statisches HTML ausliefern kann, da er jedes Mal ein neues nonce einfügen muss. Typischerweise würde der Server eine Template-Engine verwenden, um das nonce einzufügen.

Hier ist ein Ausschnitt aus Express Code, um dies zu demonstrieren:

js
function content(nonce) {
  return `
    <script nonce="${nonce}" src="/main.js"></script>
    <script nonce="${nonce}">console.log("hello!");</script>
    <h1>Hello world</h1> 
    `;
}

app.get("/", (req, res) => {
  const nonce = crypto.randomUUID();
  res.setHeader("Content-Security-Policy", `script-src 'nonce-${nonce}'`);
  res.send(content(nonce));
});

Bei jedem Request generiert der Server ein neues nonce, fügt es in die CSP ein und in die <script> Tags im zurückgegebenen Dokument ein. Beachten Sie, dass der Server:

  • ein neues nonce für jede Anfrage generiert
  • Nonces sowohl für externe als auch für Inline-Skripte verwenden kann
  • das gleiche nonce für alle <script> Tags im Dokument verwendet

Es ist wichtig, dass der Server eine Art Vorlagenverarbeitung verwendet, um Nonces einzufügen, und sie nicht einfach in alle <script>-Tags einfügt: Andernfalls könnte der Server unabsichtlich Nonces in Skripte einfügen, die von einem Angreifer eingeschleust wurden.

Beachten Sie, dass Nonces nur für Elemente verwendet werden können, die ein nonce Attribut haben: das heißt, nur <script> und <style> Elemente.

Hashes

Abrufdirektiven können auch einen Hash des Skripts verwenden, um seine Integrität zu garantieren. Bei diesem Verfahren:

  1. berechnet der Server einen Hash des Skriptinhalts mithilfe einer Hashfunktion (einer von SHA-256, SHA-384 oder SHA-512)
  2. erstellt ein Base64 Encoding des Ergebnisses
  3. fügt ein Präfix hinzu, das den verwendeten Hash-Algorithmus identifiziert (einer von sha256-, sha384- oder sha512-).

Dann fügt er das Ergebnis der Direktive hinzu:

http
Content-Security-Policy: script-src 'sha256-cd9827ad...'

Wenn der Browser das Dokument erhält, hasht er das Skript, vergleicht das Ergebnis mit dem Wert aus dem Header und lädt das Skript nur, wenn sie übereinstimmen.

Externe Skripte müssen auch das integrity Attribut enthalten, damit diese Methode funktioniert.

Hier ist ein Ausschnitt aus Express Code, um dies zu demonstrieren:

js
const hash1 = "sha256-ex2O7MWOzfczthhKm6azheryNVoERSFrPrdvxRtP8DI=";
const hash2 = "sha256-H/eahVJiG1zBXPQyXX0V6oaxkfiBdmanvfG9eZWSuEc=";

const csp = `script-src '${hash1}' '${hash2}'`;
const content = `
  <script src="./main.js" integrity="${hash2}"></script>
  <script>console.log("hello!");</script>
    <h1>Hello world</h1> 
    `;

app.get("/", (req, res) => {
  res.setHeader("Content-Security-Policy", csp);
  res.send(content);
});

Beachten Sie, dass:

  • Wir haben einen separaten Hash für jedes Skript im Dokument.
  • Für das externe Skript "main.js" fügen wir auch das integrity Attribut hinzu und geben ihm den gleichen Wert.
  • Im Gegensatz zum Beispiel mit Nonces können sowohl die CSP als auch der Inhalt statisch sein, da die Hashes gleich bleiben. Dies macht hash-basierte Richtlinien besser geeignet für statische Seiten oder Websites, die auf client-seitigem Rendering basieren.

Schema-basierte Richtlinien

Abrufdirektiven können ein Schema auflisten, wie https:, um Ressourcen zu erlauben, die mit diesem Schema geliefert werden. Dies ermöglicht es beispielsweise, eine Richtlinie festzulegen, die HTTPS für alle Ressourcennachladen erfordert:

http
Content-Security-Policy: default-src https:

Ortsbasierte Richtlinien

Abrufdirektiven können Ressourcennachladen basierend darauf kontrollieren, wo sich die Ressource befindet.

Das Stichwort 'self' erlaubt Ressourcen, die den gleichen Ursprung wie das Dokument selbst haben:

http
Content-Security-Policy: img-src 'self'

Sie können auch einen oder mehrere Hostnamen angeben, möglicherweise inklusive Wildcards. Nur Ressourcen, die von diesen Hosts geliefert werden, sind dann erlaubt. Dies könnte verwendet werden, um Inhalte von einem vertrauenswürdigen CDN zu laden.

http
Content-Security-Policy: img-src *.example.org

Sie können mehrere Orte angeben. Die folgende Direktive erlaubt nur Bilder, die denselben Ursprung wie das aktuelle Dokument haben oder von einer Subdomain von "example.org" oder von "example.com" stammen:

http
Content-Security-Policy: img-src 'self' *.example.org  example.com

Inline-JavaScript

Wenn eine CSP entweder eine default-src oder eine script-src Direktive enthält, wird Inline-JavaScript nicht ausgeführt, es sei denn, es werden zusätzliche Maßnahmen ergriffen, um es zu ermöglichen. Dies umfasst:

  • JavaScript, das sich in einem <script> Element auf der Seite befindet:

    html
    <script>
      console.log("Hello from an inline script");
    </script>
    
  • JavaScript in einem Inline-Ereignishandler-Attribut:

    html
    <img src="x" onerror="console.log('Hello from an inline event handler')" />
    
  • JavaScript in einer javascript: URL:

    html
    <a href="javascript:console.log('Hello from a javascript: URL')"></a>
    

Das Stichwort unsafe-inline kann verwendet werden, um diese Einschränkung zu übergehen. Zum Beispiel erlaubt die folgende Direktive alle Ressourcen nur mit demselben Ursprung, erlaubt jedoch Inline-JavaScript:

http
Content-Security-Policy: default-src 'self' 'unsafe-inline'

Warnung: Entwickler sollten 'unsafe-inline' vermeiden, da es einen Großteil des Zwecks einer CSP zerstört. Inline-JavaScript ist einer der häufigsten XSS-Vektoren, und eines der grundlegendsten Ziele einer CSP ist es, dessen unkontrollierte Verwendung zu verhindern.

Inline <script> Elemente sind erlaubt, wenn sie durch ein nonce oder einen hash geschützt sind, wie oben beschrieben.

Wenn eine Direktive nonce oder hash Ausdrücke enthält, wird das Stichwort unsafe-inline von Browsern ignoriert.

eval() und ähnliche APIs

Wie Inline-JavaScript wird eval() und ähnliche APIs nicht ausgeführt, wenn eine CSP entweder eine default-src oder eine script-src Direktive enthält. Dies schließt unter anderem folgende APIs ein:

  • eval() selber:

    js
    eval('console.log("hello from eval()")');
    
  • Der Function() Konstruktor:

    js
    const sum = new Function("a", "b", "return a + b");
    
  • Das String-Argument von setTimeout() und setInterval():

    js
    setTimeout("console.log('hello from setTimeout')", 1);
    

Das unsafe-eval Stichwort kann verwendet werden, um dieses Verhalten zu übergehen, und wie bei unsafe-inline sollten Entwickler unsafe-eval vermeiden. Manchmal kann es schwierig sein, Verwendungen von eval() zu entfernen: In diesen Situationen kann das Trusted Types API es sicherer machen, indem es sicherstellt, dass der Input eine definierte Richtlinie erfüllt.

Im Gegensatz zu unsafe-inline funktioniert das Stichwort unsafe-eval jedoch weiterhin auch in einer Direktive, die nonce oder hash Ausdrücke enthält.

Strikte CSP

Um das Laden von Skripten als Schutzmaßnahme gegen XSS zu kontrollieren, wird empfohlen, den nonce- oder hash- basierten Abrufdirektiven zu verwenden. Dies wird als strikte CSP bezeichnet. Diese Art von CSP hat zwei Hauptvorteile gegenüber einer ortsbasierenden CSP (gewöhnlich als Allowlist CSP genannt):

Eine nonce-basierte strikte CSP sieht so aus:

http
Content-Security-Policy:
  script-src 'nonce-{RANDOM}';
  object-src 'none';
  base-uri 'none';

In dieser CSP:

  • verwenden wir Nonces, um zu steuern, welche JavaScript-Ressourcen geladen werden dürfen
  • blockieren wir alle Objekt-Einbettungen
  • blockieren wir alle Verwendungen des <base> Elements, um eine Basis-URI festzulegen.

Eine hash-basierte strikte CSP ist gleich, außer dass sie Hashes anstelle von Nonces verwendet:

http
Content-Security-Policy:
  script-src 'sha256-{HASHED_SCRIPT}';
  object-src 'none';
  base-uri 'none';

Nonce-basierte Direktiven sind einfacher zu pflegen, wenn Sie Antworten, einschließlich des Inhalts selbst, dynamisch erzeugen können. Andernfalls müssen Sie hash-basierte Direktiven verwenden. Das Problem bei hash-basierten Direktiven ist, dass Sie den Hash neu berechnen und erneut anwenden müssen, wenn Änderungen am Skriptinhalt vorgenommen werden.

Das strict-dynamic Stichwort

Wie bereits gezeigt, ist die strikte CSP schwierig umzusetzen, wenn Sie Skripte verwenden, die nicht unter Ihrer Kontrolle stehen. Wenn ein Drittanbieter-Skript weitere Skripte lädt oder Inline-Skripte verwendet, wird dies fehlschlagen, da das Drittanbieter-Skript den nonce oder hash nicht weitergeben wird.

Das strict-dynamic Stichwort wird bereitgestellt, um bei diesem Problem zu helfen. Es ist ein Stichwort, das in eine Abrufdirektive aufgenommen werden kann, und hat den Effekt, dass wenn ein Skript einen nonce oder hash angehängt hat, dieses Skript weitere Skripte laden darf, die selbst keine Nonces oder Hashes haben. Das heißt, das Vertrauen, das in ein Skript durch einen Nonce oder Hash gesetzt wird, wird auf Skripte übertragen, die das ursprüngliche Skript lädt (und Skripte, die sie laden usw.).

Betrachten Sie zum Beispiel ein Dokument wie dieses:

html
<html lang="en-US">
  <head>
    <script
      src="./main.js"
      integrity="sha256-gEh1+8U9S1vkEuQSmmUMTZjyNSu5tIoECP4UXIEjMTk="></script>
  </head>
  <body>
    <h1>Example page!</h1>
  </body>
</html>

Es enthält ein Skript "main.js", das ein weiteres Skript "main2.js" erstellt und hinzufügt:

js
console.log("hello");

const scriptElement = document.createElement("script");
scriptElement.src = `main2.js`;

document.head.appendChild(scriptElement);

Wir liefern unser Dokument mit einer CSP wie dieser:

http
Content-Security-Policy:
  script-src 'sha256-gEh1+8U9S1vkEuQSmmUMTZjyNSu5tIoECP4UXIEjMTk='

Das "main.js"-Skript wird geladen, da sein Hash mit dem Wert in der CSP übereinstimmt. Aber sein Versuch, "main2.js" zu laden, wird fehlschlagen.

Wenn wir 'strict-dynamic' zur CSP hinzufügen, kann "main.js" "main2.js" laden:

http
Content-Security-Policy:
  script-src 'sha256-gEh1+8U9S1vkEuQSmmUMTZjyNSu5tIoECP4UXIEjMTk='
  strict-dynamic

Das 'strict-dynamic' Stichwort macht es viel einfacher, nonce- oder hash-basierte CSPs zu erstellen und zu pflegen, besonders, wenn eine Website Drittanbieter-Skripte verwendet. Es macht Ihre CSP jedoch weniger sicher, da, wenn die Skripte, die Sie einfügen, <script> Elemente basierend auf potenziellen XSS-Quellen erstellen, die CSP sie nicht schützen wird.

Inline-JavaScript und eval() refaktorisieren

Wie oben gesehen, wird Inline-JavaScript standardmäßig in einer CSP nicht erlaubt. Mit Nonces oder Hashes kann ein Entwickler Inline-<script>-Tags verwenden, aber Sie müssen immer noch den Code refaktorisieren, um andere nicht erlaubte Muster zu entfernen, einschließlich Inline-Ereignishandler, javascript: URLs und Verwendungen von eval(). Zum Beispiel sollten Inline-Ereignishandler normalerweise durch Aufrufe von addEventListener() ersetzt werden:

html
<p onclick="console.log('Hello from an inline event handler')">click me</p>
html
<!-- served with the following CSP:
 `script-src 'sha256-AjYfua7yQhrSlg807yyeaggxQ7rP9Lu0Odz7MZv8cL0='`
 -->
<p id="hello">click me</p>
<script>
  const hello = document.querySelector("#hello");
  hello.addEventListener("click", () => {
    console.log("Hello from an inline script");
  });
</script>

Clickjacking-Schutz

Die frame-ancestors Direktive kann verwendet werden, um zu steuern, welche Dokumente, falls überhaupt, erlaubt sind, dieses Dokument in einem geschachtelten Browserkontext wie einem <iframe> einzubetten. Dies ist ein effektiver Schutz gegen Clickjacking-Angriffe, da diese Angriffe davon abhängen, die Zielseite in einer vom Angreifer kontrollierten Seite einzubetten.

Die Syntax von frame-ancestors ist ein Untersetzer der Abrufdirektive-Syntax: Sie können den Einzelstichwortwert 'none' oder einen oder mehrere Quellausdrücke angeben. Allerdings sind die einzigen Quellausdrücke, die Sie verwenden können, Schemas, Hostnamen oder der 'self' Stichwortwert.

Es sei denn, Sie möchten, dass Ihre Seite einbettbar ist, sollten Sie frame-ancestors auf 'none' setzen:

http
Content-Security-Policy: frame-ancestors 'none'

Diese Direktive ist ein flexibler Ersatz für den X-Frame-Options Header.

Aufrüsten unsicherer Anfragen

Webentwickler werden dringend ermutigt, alle ihre Inhalte über HTTPS bereitzustellen. Bei der Umstellung einer Site auf HTTPS wird manchmal das Hauptdokument über HTTPS bereitgestellt, während Ressourcen über HTTP bereitgestellt werden, z. B. mit einem Markup wie diesem:

html
<script src="http://example.org/my-cat.js"></script>

Dies wird gemischter Inhalt genannt, und das Vorhandensein unsicherer Ressourcen schwächt den durch HTTPS gewährten Schutz erheblich. Gemäß dem von den Browsern implementierten gemischten Inhalt Algorithmus wird, wenn ein Dokument über HTTPS bereitgestellt wird, unsicherer Inhalt in "aufrüstbare Inhalte" und "blockierbare Inhalte" kategorisiert. Aufrüstbare Inhalte werden auf HTTPS aufgerüstet, und blockierbare Inhalte werden blockiert, was die Seite möglicherweise bricht.

Die endgültige Lösung für gemischten Inhalt besteht darin, dass Entwickler alle Ressourcen über HTTPS laden. Selbst wenn eine Site tatsächlich in der Lage ist, alle Inhalte über HTTPS bereitzustellen, kann es jedoch immer noch sehr schwierig (oder sogar praktisch unmöglich, wenn es sich um archivierte Inhalte handelt) sein, dass ein Entwickler alle URLs, die die Site verwendet, um Ressourcen zu laden, neu schreibt.

Die upgrade-insecure-requests Direktive soll dieses Problem lösen. Diese Direktive hat keinen Wert: Um sie zu setzen, fügen Sie einfach den Direktivnamen hinzu:

http
Content-Security-Policy: upgrade-insecure-requests

Wenn diese Direktive auf ein Dokument gesetzt ist, wird der Browser automatisch alle HTTP-URLs in den folgenden Fällen auf HTTPS aufrüsten:

  • Anfragen zum Laden von Ressourcen (wie Bilder, Skripte oder Schriftarten)
  • Navigationsanfragen (wie Linkziele), die gleichen Ursprungs mit dem Dokument sind
  • Navigationsanfragen in geschachtelten Browserkontexten, wie iframes
  • Formularübermittlungen

Allerdings werden Top-Level-Navigationsanfragen, deren Ziel ein anderer Ursprung ist, nicht aufgerüstet.

Nehmen wir zum Beispiel an, dass das Dokument unter https://example.org mit einer CSP bereitgestellt wird, die die upgrade-insecure-requests Direktive enthält, und das Dokument folgenden Markup enthält:

html
<script src="http://example.org/my-cat.js"></script>
<script src="http://not-example.org/another-cat.js"></script>

Der Browser wird beide dieser Anfragen automatisch auf HTTPS aufrüsten.

Angenommen, das Dokument enthält außerdem dies:

html
<a href="http://example.org/more-cats">See some more cats!</a>
<a href="http://not-example.org/even-more-cats">More cats, on another site!</a>

Der Browser wird den ersten Link auf HTTPS aufrüsten, aber nicht den zweiten, da er zu einem anderen Ursprung navigiert.

Diese Direktive ist kein Ersatz für den Strict-Transport-Security Header (auch bekannt als HSTS), da sie keine externen Links zu einer Site aufrüstet. Sites sollten diese Direktive und den Strict-Transport-Security Header einfügen.

Testen Ihrer Richtlinie

Um die Bereitstellung zu erleichtern, kann CSP im Nur-Berichtsmodus bereitgestellt werden. Die Richtlinie wird nicht durchgesetzt, aber Verstöße werden an den in der Richtlinie angegebenen Berichts-Endpunkt gesendet. Zusätzlich kann ein Nur-Berichts-Header verwendet werden, um eine zukünftige Überarbeitung einer Richtlinie zu testen, ohne sie tatsächlich bereitzustellen.

Sie können den Content-Security-Policy-Report-Only HTTP-Header verwenden, um Ihre Richtlinie anzugeben, wie folgt:

http
Content-Security-Policy-Report-Only: policy

Wenn sowohl ein Content-Security-Policy-Report-Only Header als auch ein Content-Security-Policy Header in derselben Antwort vorhanden sind, werden beide Richtlinien beachtet. Die in Content-Security-Policy Headern angegebene Richtlinie wird durchgesetzt, während die Content-Security-Policy-Report-Only Richtlinie Berichte erzeugt, aber nicht durchgesetzt wird.

Beachten Sie, dass im Gegensatz zu einer normalen Inhalts-Sicherheitsrichtlinie eine Nur-Berichts-Richtlinie nicht in einem <meta> Element geliefert werden kann.

Verstoßsmeldung

Die empfohlene Methode zum Melden von CSP-Verstößen ist die Verwendung der Reporting API, indem Endpunkte im Reporting-Endpoints deklariert werden und einer von ihnen als CSP Berichts-Ziel mithilfe der Content-Security-Policy Header report-to Direktive angegeben wird.

Warnung: Sie können auch die CSP report-uri Direktive verwenden, um eine Ziel-URL für CSP-Verstoßsmeldungen anzugeben. Dies sendet ein leicht anderes JSON-Berichtsformat über eine POST-Operation mit einem Content-Type von application/csp-report. Dieser Ansatz ist veraltet, aber Sie sollten beide erklären, bis report-to in allen Browsern unterstützt wird. Weitere Informationen zu dem Ansatz finden Sie im report-uri Thema.

Ein Server kann Clients mitteilen, wohin Berichte gesendet werden sollen, indem er den Reporting-Endpoints HTTP-Antwort-Header verwendet. Dieser Header definiert eine oder mehrere Endpunkt-URLs als kommagetrennte Liste. Um beispielsweise einen Berichts-Endpunkt namens csp-endpoint zu definieren, der Berichte unter https://example.com/csp-reports akzeptiert, könnte der Antwort-Header des Servers folgendermaßen aussehen:

http
Reporting-Endpoints: csp-endpoint="https://example.com/csp-reports"

Wenn Sie mehrere Endpunkte haben möchten, die unterschiedliche Arten von Berichten behandeln, würden Sie sie wie folgt angeben:

http
Reporting-Endpoints: csp-endpoint="https://example.com/csp-reports",
                     hpkp-endpoint="https://example.com/hpkp-reports"

Sie können dann die Content-Security-Policy Header report-to Direktive verwenden, um anzugeben, dass ein bestimmter definierter Endpunkt für Berichte verwendet werden soll. Um beispielsweise CSP-Verstoßberichte an https://example.com/csp-reports für default-src zu senden, könnten Sie folgende Antwort-Header senden:

http
Reporting-Endpoints: csp-endpoint="https://example.com/csp-reports"
Content-Security-Policy: default-src 'self'; report-to csp-endpoint

Wenn ein CSP-Verstoß auftritt, sendet der Browser den Bericht als JSON-Objekt an den angegebenen Endpunkt über eine HTTP POST-Operation, mit einem Content-Type von application/reports+json. Der Bericht ist eine serialisierte Form des Report Objekts, das eine type Eigenschaft mit einem Wert von "csp-violation" und einen body enthält, der die serialisierte Form eines CSPViolationReportBody Objekts ist.

Ein typisches Objekt könnte so aussehen:

json
{
  "age": 53531,
  "body": {
    "blockedURL": "inline",
    "columnNumber": 39,
    "disposition": "enforce",
    "documentURL": "https://example.com/csp-report",
    "effectiveDirective": "script-src-elem",
    "lineNumber": 121,
    "originalPolicy": "default-src 'self'; report-to csp-endpoint-name",
    "referrer": "https://www.google.com/",
    "sample": "console.log(\"lo\")",
    "sourceFile": "https://example.com/csp-report",
    "statusCode": 200
  },
  "type": "csp-violation",
  "url": "https://example.com/csp-report",
  "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36"
}

Sie müssen einen Server einrichten, um Berichte mit dem gegebenen JSON-Format und Inhaltstyp zu empfangen. Der Server, der diese Anfragen verarbeitet, kann dann die eingehenden Berichte auf eine Weise speichern oder verarbeiten, die am besten zu Ihren Bedürfnissen passt.

Siehe auch