Content Security Policy

Joe Medley
Joe Medley

Das Sicherheitsmodell des Webs basiert auf der Same-Origin-Richtlinie. Code aus https://mybank.com sollte nur Zugriff auf die Daten von https://mybank.com haben und https://evil.example.com auf keinen Fall Zugriff erhalten. Jeder Ursprung wird vom Rest des Webs isoliert. So erhalten Entwickler eine sichere Sandbox, in der sie entwickeln und spielen können. Theoretisch ist das absolut genial. In der Praxis haben Angreifer auf intelligente Weise Möglichkeiten gefunden, das System zu umkehren.

Bei XSS-Angriffen (Cross-Site-Scripting) wird beispielsweise dieselbe Ursprungsrichtlinie umgangen, indem eine Website dazu verleitet wird, neben dem gewünschten Inhalt schädlichen Code bereitzustellen. Dies stellt ein großes Problem dar, da Browser dem gesamten Code, der auf einer Seite angezeigt wird, als legitimer Teil der Sicherheitsherkunft dieser Seite anerkennen. Der XSS-Spickzettel bietet einen alten, aber repräsentativen Überblick über die Methoden, mit denen Angreifer möglicherweise bösartigen Code einschleusen, um gegen dieses Vertrauen zu verstoßen. Wenn ein Angreifer irgendeinen Code erfolgreich einschleust, ist das nahezu vorbei: Nutzersitzungsdaten sind kompromittiert und Informationen, die geheim gehalten werden sollten, werden an The Bad Guys ausgeschleust. Natürlich möchten wir das natürlich verhindern, wenn möglich.

In dieser Übersicht wird eine Abwehr hervorgehoben, mit der das Risiko und die Auswirkungen von XSS-Angriffen in modernen Browsern erheblich reduziert werden können: die Content Security Policy (CSP).

Kurzfassung

  • Über Zulassungslisten teilen Sie dem Kunden mit, was erlaubt ist und was nicht.
  • Informationen zu den verfügbaren Anweisungen.
  • Lernen Sie die verwendeten Keywords kennen.
  • Inline-Code und eval() gelten als schädlich.
  • Melden Sie Richtlinienverstöße vor dem Erzwingen an Ihren Server.

Zulassungslisten für Quellen

Das Problem, das von XSS-Angriffen ausgenutzt wird, besteht darin, dass der Browser nicht zwischen einem Teil der Anwendung und einem Skript unterscheiden kann, das böswillig von einem Drittanbieter eingeschleust wurde. Über die Google +1-Schaltfläche unten auf dieser Seite wird beispielsweise Code aus https://apis.google.com/js/plusone.js im Kontext des Ursprungs der Seite geladen und ausgeführt. Wir vertrauen diesem Code, aber wir können nicht erwarten, dass der Browser selbst erkennt, dass der Code von apis.google.com genial ist, während Code von apis.evil.example.com es wahrscheinlich nicht ist. Der Browser lädt jeden Code, den eine Seite anfordert, unabhängig von der Quelle glücklich herunter und führt ihn aus.

Anstatt blindlings allem, was ein Server bereitstellt, zu vertrauen, definiert die CSP den HTTP-Header Content-Security-Policy. Damit können Sie eine Zulassungsliste mit Quellen vertrauenswürdiger Inhalte erstellen und den Browser anweisen, nur Ressourcen aus diesen Quellen auszuführen oder zu rendern. Selbst wenn ein Angreifer eine Lücke finden kann, durch die das Skript eingeschleust werden kann, entspricht das Skript nicht der Zulassungsliste und wird daher nicht ausgeführt.

Da wir uns darauf vertrauen, dass apis.google.com gültigen Code liefert, und wir darauf vertrauen, dass wir das auch tun, definieren wir eine Richtlinie, die die Ausführung des Skripts nur erlaubt, wenn es aus einer dieser beiden Quellen kommt:

Content-Security-Policy: script-src 'self' https://apis.google.com

script-src ist eine Anweisung, mit der eine Reihe von skriptbezogenen Berechtigungen für eine bestimmte Seite gesteuert werden. Wir haben 'self' als gültige Skriptquelle und https://apis.google.com als eine weitere angegeben. Der Browser lädt JavaScript ordnungsgemäß von apis.google.com über HTTPS sowie vom Ursprung der aktuellen Seite herunter und führt es aus.

Konsolenfehler: Das Skript "http://evil.example.com/evil.js" sollte nicht geladen werden, da dies gegen die folgende Content Security Policy-Anweisung verstößt: script-src 'self' https://apis.google.com

Wenn diese Richtlinie definiert ist, gibt der Browser einfach einen Fehler aus, anstatt das Skript aus einer anderen Quelle zu laden. Wenn es einem cleveren Angreifer gelingt, Code in deine Website einzuschleusen, stößt er eher eine Fehlermeldung als der erwartete Erfolg.

Die Richtlinie gilt für eine Vielzahl von Ressourcen

Obwohl Skriptressourcen die offensichtlichsten Sicherheitsrisiken darstellen, bietet die CSP eine Vielzahl von Richtlinienanweisungen, die eine relativ detaillierte Kontrolle über die Ressourcen ermöglichen, die auf einer Seite geladen werden dürfen. Sie haben script-src bereits gesehen, das Konzept sollte also eindeutig sein.

Gehen wir kurz die übrigen Ressourcenanweisungen durch. Die folgende Liste enthält den Status der Anweisungen auf Ebene 2. Eine Level-3-Spezifikation wurde veröffentlicht, ist aber in den wichtigsten Browsern weitgehend nicht implementiert.

  • Mit base-uri werden die URLs eingeschränkt, die im <base>-Element einer Seite angezeigt werden können.
  • child-src listet die URLs für Worker und eingebettete Frame-Inhalte auf. Beispiel: child-src https://youtube.com ermöglicht das Einbetten von Videos von YouTube, aber nicht von anderen Quellen.
  • connect-src schränkt die Ursprünge ein, zu denen Sie eine Verbindung herstellen können (über XHR, WebSockets und EventSource).
  • font-src gibt die Quellen an, aus denen Webschriftarten bereitgestellt werden können. Die Webschriftarten von Google können über font-src https://themes.googleusercontent.com aktiviert werden.
  • form-action listet gültige Endpunkte für die Übermittlung von <form>-Tags auf.
  • frame-ancestors gibt die Quellen an, in die die aktuelle Seite eingebettet werden kann. Diese Anweisung gilt für <frame>-, <iframe>-, <embed>- und <applet>-Tags. Diese Anweisung kann nicht in <meta>-Tags verwendet werden und gilt nur für Ressourcen, die nicht auf HTML basieren.
  • frame-src wurde in Level 2 eingestellt, wird aber in Level 3 wiederhergestellt. Wenn er nicht vorhanden ist, wird er wie zuvor auf child-src zurückgesetzt.
  • img-src definiert die Ursprünge, aus denen Bilder geladen werden können.
  • media-src schränkt die Quellen ein, die für die Übermittlung von Video- und Audioinhalten zulässig sind.
  • object-src ermöglicht die Steuerung von Flash und anderen Plug-ins.
  • plugin-types begrenzt die Arten von Plug-ins, die eine Seite aufrufen kann.
  • report-uri gibt eine URL an, an die ein Browser Berichte sendet, wenn ein Verstoß gegen eine Content Security Policy vorliegt. Diese Anweisung kann nicht in <meta>-Tags verwendet werden.
  • style-src ist das Gegenstück für Stylesheets von script-src.
  • upgrade-insecure-requests weist User-Agents an, URL-Schemas umzuschreiben und HTTP zu HTTPS zu ändern. Diese Richtlinie gilt für Websites mit vielen alten URLs, die neu geschrieben werden müssen.
  • worker-src ist eine CSP-Level-3-Anweisung, die die URLs einschränkt, die als Worker, freigegebener Worker oder Service Worker geladen werden können. Seit Juli 2017 ist diese Richtlinie eingeschränkt implementiert.

Standardmäßig sind Anweisungen weit offen. Wenn Sie für eine Anweisung keine bestimmte Richtlinie festlegen, z. B. font-src, verhält sich diese Anweisung standardmäßig so, als hätten Sie * als gültige Quelle angegeben. Sie können z. B. Schriftarten von überall aus ohne Einschränkung laden.

Sie können dieses Standardverhalten überschreiben, indem Sie eine default-src-Anweisung angeben. Mit dieser Anweisung werden die Standardwerte für die meisten Anweisungen definiert, die Sie nicht angeben. Im Allgemeinen gilt dies für alle Anweisungen, die auf -src enden. Wenn default-src auf https://example.com gesetzt ist und Sie keine font-src-Anweisung angeben, können Sie Schriftarten ausschließlich aus https://example.com laden. Wir haben in unseren früheren Beispielen nur script-src angegeben. Das bedeutet, dass Bilder, Schriftarten usw. von jedem Ursprung geladen werden können.

default-src wird in den folgenden Anweisungen nicht als Fallback verwendet. Denken Sie daran: Wenn Sie sie nicht festlegen, bedeutet das, dass Sie alles zulassen.

  • base-uri
  • form-action
  • frame-ancestors
  • plugin-types
  • report-uri
  • sandbox

Sie können so viele oder so wenige dieser Anweisungen verwenden, wie es für Ihre Anwendung sinnvoll ist. Führen Sie dazu jede Anweisung im HTTP-Header auf und trennen Sie die Anweisungen jeweils durch ein Semikolon. Sie müssen alle erforderlichen Ressourcen eines bestimmten Typs in einer einzelnen Anweisung auflisten. Wenn Sie so etwas wie script-src https://host1.com; script-src https://host2.com schreiben, wird die zweite Anweisung einfach ignoriert. In etwa der folgenden würden beide Ursprünge korrekt als gültig angegeben werden:

script-src https://host1.com https://host2.com

Wenn Sie beispielsweise eine Anwendung haben, die alle Ressourcen aus einem Content Delivery Network (z. B. https://cdn.example.net) lädt und wissen, dass Sie keine in Frames eingebundenen Inhalte oder Plug-ins benötigen, sieht Ihre Richtlinie in etwa so aus:

Content-Security-Policy: default-src https://cdn.example.net; child-src 'none'; object-src 'none'

Implementierungsdetails

Sie finden die Header X-WebKit-CSP und X-Content-Security-Policy in verschiedenen Anleitungen im Web. Diese Header-Header sollten Sie in Zukunft ignorieren. Moderne Browser (mit Ausnahme von IE) unterstützen den Header Content-Security-Policy ohne Präfix. Das ist die Überschrift, die Sie verwenden sollten.

Unabhängig vom verwendeten Header wird die Richtlinie auf Seitenbasis definiert: Sie müssen den HTTP-Header zusammen mit jeder Antwort senden, die geschützt werden soll. Dies bietet ein hohes Maß an Flexibilität, da Sie die Richtlinie für bestimmte Seiten entsprechend ihren spezifischen Anforderungen optimieren können. Vielleicht verfügt eine Gruppe von Seiten auf Ihrer Website über eine +1-Schaltfläche und andere nicht: Sie könnten zulassen, dass der Schaltflächencode nur bei Bedarf geladen wird.

Die Quellenliste in den einzelnen Anweisungen ist flexibel. Sie können Quellen nach Schema (data:, https:) oder mit einer Spezifität von nur Hostname (example.com, was jedem Ursprung auf diesem Host entspricht: beliebiges Schema, beliebiger Port) bis zu einem voll qualifizierten URI (https://example.com:443, der nur HTTPS, nur example.com und nur Port 443 entspricht) angeben. Platzhalter werden nur als Schema, Port oder ganz links im Hostnamen akzeptiert: *://*.example.com:* stimmt mit allen Subdomains von example.com (aber nicht von example.com selbst) mit einem beliebigen Schema und an jedem Port überein.

Die Quellenliste akzeptiert außerdem vier Keywords:

  • Für 'none' liegen keine Übereinstimmungen vor.
  • 'self' stimmt mit dem aktuellen Ursprung überein, aber nicht mit seinen Subdomains.
  • In 'unsafe-inline' ist Inline-JavaScript und -CSS zulässig. (Wir kommen später noch ausführlicher darauf zurück.)
  • 'unsafe-eval' ermöglicht Text-in-JavaScript-Mechanismen wie eval. (Auch darauf kommen wir gleich.)

Diese Keywords erfordern einfache Anführungszeichen. Beispiel: script-src 'self' (mit Anführungszeichen) autorisiert die Ausführung von JavaScript auf dem aktuellen Host. script-src self (ohne Anführungszeichen) lässt JavaScript von einem Server namens „self“ (und nicht vom aktuellen Host) zu, was wahrscheinlich nicht das ist, was Sie gemeint haben.

Sandbox-Technologie

Es gibt noch eine weitere Anweisung, über die wir gesprochen werden sollten: sandbox. Es unterscheidet sich ein wenig von den anderen, die wir uns angesehen haben, da hier die Aktionen, die eine Seite ausführen kann, und nicht die Ressourcen, die sie laden kann, eingeschränkt werden. Wenn die Anweisung sandbox vorhanden ist, wird die Seite so behandelt, als wäre sie innerhalb einer <iframe> mit einem sandbox-Attribut geladen. Dies kann viele verschiedene Auswirkungen auf die Seite haben: Sie müssen unter anderem einen eindeutigen Ursprung für die Seite festlegen und das Senden von Formularen verhindern. Alle Details zu gültigen Sandbox-Attributen finden Sie im Abschnitt „Sandboxing“ der HTML5-Spezifikation.

Das Meta-Tag

Der bevorzugte Übermittlungsmechanismus von CSPs ist ein HTTP-Header. Es kann jedoch nützlich sein, eine Richtlinie auf einer Seite direkt im Markup festzulegen. Dazu verwendest du ein <meta>-Tag mit einem http-equiv-Attribut:

<meta
  http-equiv="Content-Security-Policy"
  content="default-src https://cdn.example.net; child-src 'none'; object-src 'none'"
/>

Dies kann nicht für frame-ancestors, report-uri oder sandbox verwendet werden.

Inline-Code gilt als schädlich

Es sollte klar sein, dass die CSP auf der Quelle der Zulassungsliste basiert. So wird der Browser eindeutig angewiesen, bestimmte Ressourcengruppen als akzeptabel zu behandeln und den Rest abzulehnen. Ursprungsbasierte Zulassungslisten lösen jedoch nicht die größte Bedrohung durch XSS-Angriffe: Inline-Script-Injection. Wenn ein Angreifer ein Skript-Tag einschleusen kann, das direkt schädliche Nutzlasten enthält (<script>sendMyDataToEvilDotCom();</script>), hat der Browser keinen Mechanismus, um dieses Tag von einem legitimen Inline-Skript-Tag zu unterscheiden. Die CSP löst dieses Problem, indem Inline-Skripts vollständig gesperrt werden. Dies ist die einzige Möglichkeit, um sicherzugehen.

Diese Sperre umfasst nicht nur Skripts, die direkt in script-Tags eingebettet sind, sondern auch Inline-Event-Handler und javascript:-URLs. Du musst den Inhalt von script-Tags in eine externe Datei verschieben und javascript:-URLs und <a ... onclick="[JAVASCRIPT]"> durch entsprechende addEventListener()-Aufrufe ersetzen. Sie können beispielsweise Folgendes umschreiben aus:

<script>
  function doAmazingThings() {
    alert('YOU AM AMAZING!');
  }
</script>
<button onclick="doAmazingThings();">Am I amazing?</button>

in etwa so aussehen:

<!-- amazing.html -->
<script src="amazing.js"></script>
<button id="amazing">Am I amazing?</button>

<div style="clear:both;"></div>
// amazing.js
function doAmazingThings() {
  alert('YOU AM AMAZING!');
}
document.addEventListener('DOMContentLoaded', function () {
  document.getElementById('amazing').addEventListener('click', doAmazingThings);
});

Der umgeschriebene Code hat eine Reihe von Vorteilen, die über die gute Zusammenarbeit mit CSP hinausgehen. Er gehört bereits zu den Best Practices, unabhängig davon, wie Sie CSP verwenden. Inline-JavaScript kombiniert Struktur und Verhalten auf genau die Art und Weise, wie Sie es nicht sollten. Externe Ressourcen können von Browsern einfacher im Cache gespeichert werden, sind für Entwickler verständlicher und erleichtern die Kompilierung und Reduzierung. Sie werden besseren Code schreiben, wenn Sie die Arbeit übernehmen, um Code in externe Ressourcen zu verschieben.

Inline-Stile werden gleich behandelt: Sowohl das Attribut style als auch die Tags style sollten in externen Stylesheets konsolidiert werden, um vor einer Vielzahl überraschend cleverer Methoden zur Daten-Exfiltration zu schützen, die CSS ermöglicht.

Wenn Sie Inline-Script und -stil benötigen, können Sie diese aktivieren, indem Sie 'unsafe-inline' als zulässige Quelle in einer script-src- oder style-src-Anweisung hinzufügen. Sie können auch eine Nonce oder einen Hash verwenden (siehe unten), sollten das aber unbedingt tun. Das Sperren von Inline-Skripts ist der größte Sicherheitsgewinn, den CSP bietet, und das Sperren von Inline-Style härtet Ihre Anwendung ebenfalls. Es ist ein wenig Aufwand erforderlich, um sicherzustellen, dass nach dem Verschieben des gesamten Codes alles richtig funktioniert, aber dieser Kompromiss ist lohnenswert.

Wenn Sie es unbedingt verwenden müssen

CSP-Level 2 bietet Abwärtskompatibilität für Inline-Skripts, da Sie der Zulassungsliste bestimmte Inline-Skripts mit einer kryptografischen Nonce (einmalige Nummer) oder einem Hash hinzufügen können. Dies kann umständlich sein, ist aber im kleinen Rahmen nützlich.

Wenn Sie eine Nonce verwenden möchten, müssen Sie Ihrem Script-Tag ein Nonce-Attribut zuweisen. Der Wert muss mit einem Wert in der Liste der vertrauenswürdigen Quellen übereinstimmen. Beispiel:

<script nonce="EDNnf03nceIOfn39fn3e9h3sdfa">
  // Some inline code I can't remove yet, but need to asap.
</script>

Fügen Sie nun die Nonce der script-src-Anweisung hinzu, die an das Keyword nonce- angehängt wird.

Content-Security-Policy: script-src 'nonce-EDNnf03nceIOfn39fn3e9h3sdfa'

Die Nonces müssen für jede Seitenanfrage neu generiert werden und dürfen nicht unangemessen sein.

Hashes funktionieren fast auf die gleiche Weise. Anstatt dem Skript-Tag Code hinzuzufügen, erstellen Sie einen SHA-Hash des Skripts selbst und fügen Sie ihn der script-src-Anweisung hinzu. Nehmen wir beispielsweise an, Ihre Seite enthielt Folgendes:

<script>
  alert('Hello, world.');
</script>

Ihre Richtlinie würde Folgendes enthalten:

Content-Security-Policy: script-src 'sha256-qznLcsROx4GACP2dm0UCKCzCG-HiZ1guq6ZZDob_Tng='

Hier sind einige Dinge zu beachten. Das Präfix sha*- gibt den Algorithmus an, der den Hash generiert. Im obigen Beispiel wird sha256- verwendet. Die CSP unterstützt auch sha384- und sha512-. Geben Sie beim Generieren des Hash-Werts nicht die <script>-Tags an. Auch Groß- und Kleinschreibung sowie Leerzeichen sind von Bedeutung, einschließlich voran- und nachgestellter Leerzeichen.

Eine Google-Suche zum Generieren von SHA-Hashes liefert Ihnen Lösungen in beliebig vielen Sprachen. Wenn Sie Chrome 40 oder höher verwenden, können Sie die Entwicklertools öffnen und dann Ihre Seite aktualisieren. Der Tab „Console“ enthält Fehlermeldungen mit dem richtigen SHA256-Hash für jedes Inline-Script.

Auch bewerten

Selbst wenn ein Angreifer das Skript nicht direkt einschleusen kann, könnte er Ihre Anwendung dazu verleiten, ansonsten inaktiven Text in ausführbares JavaScript zu konvertieren und in seinem Namen auszuführen. eval(), neue Functions() , setTimeout([string], ...) und setInterval([string], ...) sind Vektoren, über die injizierter Text am Ende etwas unerwartet schädliches ausführen kann. Die Standardreaktion der CSP auf dieses Risiko besteht darin, alle diese Vektoren vollständig zu blockieren.

Dies hat mehr als nur einige Auswirkungen auf die Art und Weise, wie Sie Anwendungen erstellen:

  • Sie müssen JSON über das integrierte JSON.parse parsen, anstatt eval zu verwenden. Native JSON-Vorgänge sind in jedem Browser seit IE8 verfügbar und absolut sicher.
  • Schreiben Sie alle setTimeout- oder setInterval-Aufrufe um, die Sie derzeit mit Inline-Funktionen statt mit Strings ausführen. Beispiel:
setTimeout("document.querySelector('a').style.display = 'none';", 10);

besser geschrieben als:

setTimeout(function () {
  document.querySelector('a').style.display = 'none';
}, 10);
  • Vermeiden Sie Inline-Vorlagen zur Laufzeit: Viele Vorlagenbibliotheken verwenden new Function() großzügig, um die Vorlagenerstellung während der Laufzeit zu beschleunigen. Es ist eine raffinierte Anwendung der dynamischen Programmierung, birgt jedoch das Risiko, dass schädlicher Text bewertet wird. Einige Frameworks unterstützen CSP standardmäßig und nutzen einen robusten Parser, falls eval nicht vorhanden ist. Ein gutes Beispiel hierfür ist die Anweisung ng-csp von AngularJS.

Die bessere Wahl wäre jedoch eine Vorlagensprache, die eine Vorkompilierung ermöglicht (z. B. Handlebars tut). Durch das Vorkompilieren der Vorlagen wird der Vorgang für Nutzer noch schneller als bei der schnellsten Laufzeitimplementierung. Außerdem ist sie sicherer. Wenn "eval" und seine Text-zu-JavaScript-Brüder für Ihre Anwendung erforderlich sind, können Sie sie aktivieren, indem Sie 'unsafe-eval' als zulässige Quelle in einer script-src-Anweisung hinzufügen. Wir raten jedoch dringend davon ab. Wenn Sie die Möglichkeit zum Ausführen von Strings sperren, erschweren Sie es Angreifern, nicht autorisierten Code auf Ihrer Website auszuführen.

Berichterstellung

Die Fähigkeit von CSP, nicht vertrauenswürdige Ressourcen clientseitig zu blockieren, ist ein großer Gewinn für Ihre Nutzer. Es wäre jedoch sehr hilfreich, eine Art Benachrichtigung an den Server senden zu lassen, damit Sie alle Fehler identifizieren und beheben können, die eine schädliche Injektion ermöglichen. Dazu können Sie den Browser anweisen, POST-Verstoßberichte im JSON-Format an einen in einer report-uri-Anweisung angegebenen Speicherort zu senden.

Content-Security-Policy: default-src 'self'; ...; report-uri /my_amazing_csp_report_parser;

Diese Berichte sehen in etwa so aus:

{
  "csp-report": {
    "document-uri": "http://example.org/page.html",
    "referrer": "http://evil.example.com/",
    "blocked-uri": "http://evil.example.com/evil.js",
    "violated-directive": "script-src 'self' https://apis.google.com",
    "original-policy": "script-src 'self' https://apis.google.com; report-uri http://example.org/my_amazing_csp_report_parser"
  }
}

Dieser enthält viele Informationen, mit denen Sie die Ursache des Verstoßes ermitteln können, darunter die Seite, auf der der Verstoß aufgetreten ist (document-uri), die Verweis-URL dieser Seite (im Gegensatz zum HTTP-Header-Feld ist der Schlüssel nicht falsch geschrieben), die Ressource, die gegen die Richtlinie der Seite verstößt (blocked-uri), die spezifische Anweisung, gegen die sie verstoßen hat (violated-directive) und die vollständige Richtlinie der Seite (original-policy).

Nur Bericht

Wenn Sie gerade erst mit CSP beginnen, ist es sinnvoll, den aktuellen Status Ihrer Anwendung zu bewerten, bevor Sie eine drakonische Richtlinie für Ihre Nutzer einführen. Als Sprungbrett für eine vollständige Bereitstellung können Sie den Browser auffordern, eine Richtlinie zu überwachen und Verstöße zu melden, ohne die Einschränkungen durchzusetzen. Senden Sie anstelle eines Content-Security-Policy-Headers einen Content-Security-Policy-Report-Only-Header.

Content-Security-Policy-Report-Only: default-src 'self'; ...; report-uri /my_amazing_csp_report_parser;

Die im Berichterstellungsmodus angegebene Richtlinie blockiert keine eingeschränkten Ressourcen, sendet aber Berichte über Verstöße an den von Ihnen angegebenen Standort. Sie können sogar beide Header senden und so eine Richtlinie erzwingen, während eine andere überwacht wird. Dies ist eine gute Möglichkeit, die Auswirkungen von Änderungen an der CSP Ihrer Anwendung zu bewerten: Aktivieren Sie die Berichterstellung für eine neue Richtlinie, überwachen Sie die gemeldeten Verstöße und beheben Sie eventuell auftretende Fehler. Wenn Sie mit deren Auswirkungen zufrieden sind, können Sie mit der Durchsetzung der neuen Richtlinie beginnen.

Nutzung in der Praxis

CSP 1 lässt sich in Chrome, Safari und Firefox problemlos verwenden, bietet in IE 10 jedoch nur begrenzte Unterstützung. Weitere Informationen finden Sie unter caniuse.com. CSP Level 2 ist seit Version 40 in Chrome verfügbar. Der Header wurde auf großen Websites wie Twitter und Facebook bereitgestellt (Fallstudie von Twitter ist es wert, zu lesen) und der Standard ist bereits für die Implementierung auf Ihren eigenen Websites bereit.

Der erste Schritt zum Erstellen einer Richtlinie für Ihre Anwendung besteht darin, die Ressourcen zu bewerten, die Sie tatsächlich laden. Wenn Sie der Meinung sind, dass Sie die Zusammensetzung Ihrer App in der App im Blick haben, richten Sie basierend auf diesen Anforderungen eine Richtlinie ein. Sehen wir uns einige häufige Anwendungsfälle an und überlegen, wie wir sie innerhalb der Schutzgrenzen der CSP am besten unterstützen können.

Anwendungsfall Nr. 1: Social-Media-Widgets

  • Die +1-Schaltfläche von Google enthält ein Skript von https://apis.google.com und bettet eine <iframe> von https://plusone.google.com ein. Sie benötigen eine Richtlinie, die beide Ursprünge enthält, um die Schaltfläche einzubetten. Eine Mindestrichtlinie wäre script-src https://apis.google.com; child-src https://plusone.google.com. Außerdem muss das von Google bereitgestellte JavaScript-Snippet in eine externe JavaScript-Datei übernommen werden. Wenn Sie eine Richtlinie der Ebene 1 mit frame-src hatten, mussten Sie sie in Stufe 2 in child-src ändern. In CSP-Level 3 ist dies nicht mehr erforderlich.

  • Die Like-Schaltfläche von Facebook bietet eine Reihe von Implementierungsoptionen. Wir empfehlen, bei der <iframe>-Version zu bleiben, da sie sicher in einer Sandbox vom Rest deiner Website ausgeführt wird. Damit sie richtig funktioniert, ist eine child-src https://facebook.com-Anweisung erforderlich. Beachten Sie, dass der von Facebook bereitgestellte <iframe>-Code standardmäßig eine relative URL lädt: //facebook.com. Ändern Sie die Einstellung, um HTTPS explizit anzugeben: https://facebook.com. Es gibt keinen Grund, HTTP zu verwenden, wenn es nicht notwendig ist.

  • Die Tweet-Schaltfläche von Twitter erfordert Zugriff auf ein Skript und einen Frame, die beide unter https://platform.twitter.com gehostet werden. Twitter stellt standardmäßig auch eine relative URL bereit. Bearbeiten Sie den Code so, dass HTTPS angegeben wird, wenn Sie ihn lokal kopieren/einfügen. script-src https://platform.twitter.com; child-src https://platform.twitter.com ist einsatzbereit, solange Sie das von Twitter bereitgestellte JavaScript-Snippet in eine externe JavaScript-Datei verschieben.

  • Andere Plattformen haben ähnliche Anforderungen und können auf ähnliche Weise angegangen werden. Wir empfehlen, nur für default-src den Wert 'none' festzulegen und die Ressourcen in der Konsole zu beobachten, um festzustellen, welche Ressourcen Sie aktivieren müssen, damit die Widgets funktionieren.

Das Hinzufügen mehrerer Widgets ist unkompliziert: Kombinieren Sie einfach die Richtlinienanweisungen und denken Sie daran, alle Ressourcen eines einzelnen Typs in einer einzigen Anweisung zusammenzuführen. Wenn Sie alle drei Social-Media-Widgets verwenden möchten, würde die Richtlinie wie folgt aussehen:

script-src https://apis.google.com https://platform.twitter.com; child-src https://plusone.google.com https://facebook.com https://platform.twitter.com

Anwendungsfall 2: Sperren

Nehmen wir für einen Moment an, dass Sie eine Bankenwebsite betreiben und sicherstellen möchten, dass nur die von Ihnen selbst geschriebenen Ressourcen geladen werden können. Beginnen Sie in diesem Szenario mit einer Standardrichtlinie, die absolut alles blockiert (default-src 'none'), und bauen Sie darauf auf.

Angenommen, die Bank lädt alle Bilder, alle Stile und Skripts aus einem CDN bei https://cdn.mybank.net und stellt über XHR eine Verbindung zu https://api.mybank.com/ her, um verschiedene Datenelemente abzurufen. Frames werden nur für lokale Seiten der Website verwendet und nicht für die Herkunft Dritter. Es gibt kein Flash auf der Website, keine Schriftarten oder Extras. Der restriktivste CSP-Header, den wir senden könnten, lautet:

Content-Security-Policy: default-src 'none'; script-src https://cdn.mybank.net; style-src https://cdn.mybank.net; img-src https://cdn.mybank.net; connect-src https://api.mybank.com; child-src 'self'

Anwendungsfall 3: Nur SSL

Der Administrator eines Ehering-Diskussionsforums möchte sicherstellen, dass alle Ressourcen nur über sichere Kanäle geladen werden, er schreibt aber nicht wirklich viel Code. Das Umschreiben großer Teile der mit Inline-Skript und Stil gefüllten Drittanbieter-Forensoftware übersteigt seine Möglichkeiten. Die folgende Richtlinie ist dann wirksam:

Content-Security-Policy: default-src https:; script-src https: 'unsafe-inline'; style-src https: 'unsafe-inline'

Obwohl https: in default-src angegeben ist, übernehmen die Skript- und Stilanweisungen diese Quelle nicht automatisch. Jede Anweisung überschreibt den Standardwert für diesen spezifischen Ressourcentyp vollständig.

Die Zukunft

Content Security Policy Level 2 ist eine Kandidatenempfehlung. Die Arbeitsgruppe zur Sicherheit von Webanwendungen des W3C hat bereits mit der Arbeit an der nächsten Iteration der Spezifikation, Content Security Policy Level 3, begonnen.

Wenn Sie an den Diskussionen über diese neuen Funktionen interessiert sind, überfliegen Sie die Public-Web-appsec@ Mailinglisten-Archive oder melden Sie sich selbst an.

Feedback