Dieser Inhalt wurde automatisch aus dem Englischen übersetzt, und kann Fehler enthalten.Erfahre mehr über dieses Experiment.
Content Security Policy (CSP)
Content Security Policy (CSP) ist ein Feature, das hilft, das Risiko bestimmter Arten von Sicherheitsbedrohungen zu verhindern oder zu minimieren. Es besteht aus einer Reihe von Anweisungen von einer Website an einen Browser, die diesem vorschreiben, Einschränkungen für die Dinge zu setzen, die der Code der Seite ausführen darf.
Der primäre Anwendungsfall für CSP ist die Kontrolle darüber, welche Ressourcen, insbesondere JavaScript-Ressourcen, ein Dokument laden darf. Dies wird hauptsächlich als Schutz gegenCross-Site Scripting (XSS)-Angriffe verwendet, bei denen ein Angreifer bösartigen Code in die Seite des Opfers einschleusen kann.
Eine CSP kann auch andere Zwecke erfüllen, wie beispielsweise den Schutz vorClickjacking und die Unterstützung der Sicherstellung, dass die Seiten einer Website über HTTPS geladen werden.
In diesem Leitfaden beginnen wir damit, zu beschreiben, wie eine CSP an einen Browser übermittelt wird und wie sie auf einer hohen Ebene aussieht.
Dann beschreiben wir, wie sie verwendet werden kann, um:
- Kontrollieren, welche Ressourcen geladen werden, um XSS zu verhindern.
- Einbettung einschränken, um Clickjacking zu verhindern.
- Unsichere Anfragen aktualisieren, um sicherzustellen, dass alle Ressourcen über HTTPS bereitgestellt werden.
- Die Verwendung von vertrauenswürdigen Typen verlangen, um Client-seitiges XSS abzuwehren.
Beachten Sie, dass es keine Abhängigkeit zwischen den verschiedenen Anwendungsfällen gibt: Wenn Sie Clickjacking-Schutz hinzufügen möchten, aber keine XSS-Abwehr, können Sie einfach die Direktiven für diesen Anwendungsfall hinzufügen.
Abschließend beschreiben wirStrategien zur Einführung einer CSP und Werkzeuge, die diesen Prozess erleichtern können.
In diesem Artikel
CSP-Überblick
Eine CSP sollte imContent-Security-Policy Antwort-Header an den Browser übermittelt werden. Sie sollte bei allen Antworten auf alle Anfragen gesetzt werden, nicht nur beim Hauptdokument.
Sie können sie auch mit demhttp-equiv Attribut des<meta> Elements Ihres Dokuments angeben, was für einige Anwendungsfälle nützlich ist, wie etwa ein clientseitig gerendertesSingle Page App, das nur statische Ressourcen hat, da Sie so vermeiden können, auf irgendwelche Serverinfrastruktur angewiesen zu sein. Diese Option unterstützt jedoch nicht alle CSP-Funktionen.
Die Richtlinie wird als eine Reihe vonDirektiven angegeben, getrennt durch Semikolons. Jede Direktive kontrolliert einen anderen Aspekt der Sicherheitsrichtlinie. Jede Direktive besteht aus einem Namen, gefolgt von einem Leerzeichen und einem Wert. Unterschiedliche Direktiven können unterschiedliche Syntaxen haben.
Zum Beispiel betrachten wir die folgende CSP:
Content-Security-Policy: default-src 'self'; img-src 'self' example.comSie setzt zwei Direktiven:
- die
default-srcDirektive ist auf'self'gesetzt - die
img-srcDirektive ist auf'self' example.comgesetzt.
Die erste Direktive,default-src, weist den Browser an, nur Ressourcen zu laden, die dieselbe Herkunft wie das Dokument haben, 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 dieselbe Herkunft haben oder vonexample.com bereitgestellt werden.
Im nächsten Abschnitt betrachten wir die Werkzeuge zur Kontrolle von Ressourcenladevorgängen, was die Hauptfunktion einer CSP darstellt.
Kontrolle von Ressourcenladevorgängen
Eine CSP kann verwendet werden, um die Ressourcen zu kontrollieren, die ein Dokument laden darf. Dies wird primär zum Schutz vor Cross-Site Scripting (XSS)-Angriffen eingesetzt.
In diesem Abschnitt werden wir zuerst sehen, wie die Kontrolle von Ressourcenladevorgängen helfen kann, XSS zu verhindern, und dann die Werkzeuge betrachten, die CSP bereitstellt, um zu kontrollieren, welche Ressourcen geladen werden. Schließlich beschreiben wir eine spezielle empfohlene Strategie, die als "Strikte CSP" bezeichnet wird.
XSS und Ressourcenladevorgänge
Ein Cross-Site Scripting (XSS)-Angriff ist einer, bei dem ein Angreifer in der Lage ist, seinen Code im Kontext der Zielwebsite auszuführen. Dieser Code kann dann alles tun, was auch der eigene Code der Website könnte, einschließlich zum Beispiel:
- den Inhalt der geladenen Seiten der Website zuzugreifen oder zu modifizieren
- auf Inhalte im lokalen Speicher zuzugreifen oder diese zu modifizieren
- HTTP-Anfragen mit den Berechtigungen des Benutzers zu stellen, was es dem Angreifer ermöglicht, den Benutzer zu täuschen oder auf sensible Daten zuzugreifen
Ein XSS-Angriff ist möglich, wenn eine Website einige Eingaben akzeptiert, die von einem Angreifer erstellt worden sein könnten (zum Beispiel URL-Parameter oder ein Kommentar zu einem Blog-Post), und diese dann in die Seite einfügt, ohne sie zuzu bereinigen: das heißt, ohne sicherzustellen, dass sie nicht als JavaScript ausgeführt werden können.
Websites sollten sich durch Bereinigung dieser Eingaben vor XSS schützen, bevor sie sie in die Seite einfügen.
Hinweis:Eine CSP kann tatsächlich auf zwei verschiedene Arten helfen, sich vor XSS zu schützen:
- Sie kann sicherstellen, dass Eingaben bereinigt werden, bevor sie auf dem Client verwendet werden: wir besprechen dies später im AbschnittVertrauenswürdige Typen verlangen.
- Durch Kontrolle der Ressourcenladevorgänge kann eine CSP einen Schutz in der Tiefe gegen XSS bieten und die Website selbst dann schützen, wenn die Bereinigung fehlschlägt. Dies ist die XSS-Abwehr, die wir in diesem Abschnitt diskutieren werden.
Wenn die Bereinigung fehlschlägt, gibt es verschiedene Formen, die der injizierte 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!`)" src="thumbnail.jpg" alt="" />Eine
#"#"></iframe>
Ein String-Argument für eine unsichere API wieeval():
eval("console.log(`You've been hacked!`)");Durch die Kontrolle von Ressourcenladevorgängen kann eine CSP Schutz gegen all dies bieten. Mit einer CSP können Sie:
- die erlaubten Quellen für JavaScript-Dateien und andere Ressourcen festlegen und effektiv Ladevorgänge von
https://evil.example.comblockieren - inline Skript-Tags deaktivieren
- nur Skript-Tags zulassen, die den richtigenNonce oder Hash gesetzt haben
- Inline-Ereignishandler deaktivieren
#"fetch-direktiven" >Fetch-Direktiven
Fetch-Direktiven werden verwendet, um eine bestimmte Kategorie von Ressourcen anzugeben, die ein Dokument laden darf — wie JavaScript, CSS-Stylesheets, Bilder, Schriftarten usw.
Es gibt verschiedene Fetch-Direktiven für unterschiedliche Arten von Ressourcen. Zum Beispiel:
script-srclegt erlaubte Quellen für JavaScript fest.style-srclegt erlaubte Quellen für CSS-Stylesheets fest.img-srclegt erlaubte Quellen für Bilder fest.
Eine spezielle Fetch-Direktive ist
default-src, die eine Fallback-Richtlinie für alle Ressourcen festlegt, deren Direktiven nicht explizit aufgelistet sind.Für die vollständige Sammlung von Fetch-Direktiven siehe dieReferenzdokumentation.
Jede Fetch-Direktive wird entweder als einzelnes Schlüsselwort
'none'oder als eine oder mehrereQuellausdrücke, getrennt durch Leerzeichen, spezifiziert. Wenn mehr als ein Quellausdruck aufgeführt ist: Wenn eine der Methoden die Ressource erlaubt, wird die Ressource zugelassen.Zum Beispiel setzt die folgende CSP zwei Fetch-Direktiven:
default-srcerhält den Einzel-Quellausdruck'self'img-srcerhält zwei Quellausdrücke:'self'undexample.com
Die Wirkung davon ist, dass:
- Bilder entweder von der gleichen Herkunft wie das Dokument stammen oder von
example.comgeladen werden müssen - alle anderen Ressourcen von derselben Herkunft wie das Dokument stammen müssen.
In den folgenden Abschnitten beschreiben wir einige der Möglichkeiten, wie Sie Quellausdrücke verwenden können, um Ressourcenladevorgänge zu kontrollieren. Beachten Sie, dass, obwohl wir sie separat beschreiben, diese Ausdrücke im Allgemeinen kombiniert werden können: Beispielsweise kann eine einzelne Fetch-Direktive Nonces sowie Hostnamen enthalten.
Ressourcen blockieren
Um eine Ressourcentype vollständig zu blockieren, verwenden Sie das Schlüsselwort
'none'. Zum Beispiel blockiert die folgende Direktive alle<object>und<embed>Ressourcen:httpContent-Security-Policy: object-src 'none'Beachten Sie, dass
'none'nicht mit einer anderen Methode in einer bestimmten Direktive kombiniert werden darf: In der Praxis, wenn andere Quellausdrücke zusammen mit'none'angegeben werden, werden sie ignoriert.Nonces
Ein
nonceist der empfohlene Ansatz, um das Laden von<script>und<style>Ressourcen einzuschränken.Mit einem Nonce generiert der Server für jede HTTP-Antwort einen Zufallswert und fügt ihn in eine
script-srcund/oder einestyle-srcDirektive ein:httpContent-Security-Policy: script-src 'nonce-416d1177-4d12-4e3b-b7c9-f6c409789fb8'Der Server fügt dann diesen Wert als Wert des
nonceAttributs für alle<script>und/oder<style>Tags ein, die sie im Dokument beabsichtigen, einzuschließen.Der Browser vergleicht die beiden Werte und lädt die Ressource nur, wenn sie übereinstimmen. Die Idee ist, dass selbst wenn ein Angreifer etwas JavaScript in die Seite einfügen kann, sie nicht wissen, welchen Nonce der Server verwendet, sodass der Browser das Skript nicht ausführt.
Damit dieser Ansatz funktioniert, darf es nicht möglich sein, dass ein Angreifer den Nonce errät.
In der Praxis bedeutet das, dass der Nonce für jede HTTP-Antwort unterschiedlich sein muss und nicht vorhersagbar sein darf.
Dies bedeutet wiederum, dass der Server kein statisches HTML bereitstellen kann, da er jedes Mal einen neuen Nonce einfügen muss. Normalerweise würde der Server eine Templating-Engine verwenden, um den Nonce einzufügen.
Hier ist ein Ausschnitt ausExpress Code, um dies zu demonstrieren:
jsfunction 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 jeder Anfrage generiert der Server einen neuen Nonce, fügt ihn in die CSP und in die
<script>Tags im zurückgegebenen Dokument ein. Beachten Sie, dass der Server:- für jede Anfrage einen neuen Nonce generiert
- Nonces sowohl mit externen als auch Inline-Skripten verwenden kann
- den gleichen Nonce für alle
<script>Tags im Dokument verwendet
Es ist wichtig, dass der Server eine Art Templating benutzt, um Nonces einzufügen, und sie nicht einfach in alle
<script>Tags einfügt: sonst könnte der Server versehentlich 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
nonceAttribut haben: das heißt, nur<script>und<style>Elemente.Hashes
Fetch-Direktiven können auch einen Hash des Skripts verwenden, um seine Integrität zu garantieren. Bei dieser Methode:
- berechnet der Server einen Hash der Skriptinhalte mit einerHash-Funktion (eine von SHA-256, SHA-384 oder SHA-512)
- erstellt er eineBase64 Kodierung des Ergebnisses
- fügt er einen Präfix hinzu, der den verwendeten Hash-Algorithmus identifiziert (einer von
sha256-,sha384-odersha512-).
Dann fügt er das Ergebnis der Direktive hinzu:
httpContent-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 Skripten müssen auch das
integrityAttribut enthalten, damit diese Methode funktioniert.Hier ist ein Ausschnitt von Express-Code, um dies zu demonstrieren:
jsconst 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
integrityAttribut 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 sich die Hashes nicht ändern. Dies macht Hash-basierte Richtlinien besser geeignet für statische Seiten oder Websites, die auf clientseitigem Rendering beruhen.
Schema-basierte Richtlinien
Fetch-Direktiven können ein Schema auflisten, wie
https:, um Ressourcen zuzulassen, die über dieses Schema bereitgestellt werden. Dies erlaubt es einer Richtlinie beispielsweise, HTTPS für alle Ressourcenladevorgänge zu verlangen:httpContent-Security-Policy: default-src https:Ortsbasierte Richtlinien
Fetch-Direktiven können Ressourcenladevorgänge basierend auf dem Ort, an dem sich die Ressource befindet, kontrollieren.
Das Schlüsselwort
'self'erlaubt Ressourcen, die vom selben Ursprung wie das Dokument selbst stammen:httpContent-Security-Policy: img-src 'self'Sie können auch einen oder mehrere Hostnamen angeben, möglicherweise mit Wildcards, und nur Ressourcen, die von diesen Hosts bereitgestellt werden, sind erlaubt. Dies könnte beispielsweise verwendet werden, um Inhalte zuzulassen, die von einem vertrauenswürdigen CDN bereitgestellt werden.
httpContent-Security-Policy: img-src *.example.orgSie können mehrere Standorte angeben. Die folgende Direktive erlaubt nur Bilder, die vom selben Ursprung wie das aktuelle Dokument stammen, oder von einer Subdomain von "example.org", oder von "example.com" bereitgestellt werden:
httpContent-Security-Policy: img-src 'self' *.example.org example.comInline-JavaScript
Wenn eine CSP entweder eine
default-srcoder einescript-srcDirektive enthält, dann darf Inline-JavaScript nicht ausgeführt werden, es sei denn, es werden zusätzliche Maßnahmen getroffen, um es zu ermöglichen. Dies schließt ein:JavaScript, das in einem
<script>Element auf der Seite enthalten ist:html<script> console.log("Hello from an inline script");</script>JavaScript in einem Inline-Ereignishandlerattribut:
html<img src="x" onerror="console.log('Hello from an inline event handler')" />JavaScript in einer
#"#">Click me</a>