Content Security Policy

Joe Medley
Joe Medley

Das Sicherheitsmodell des Web basiert auf der Richtlinie für denselben Ursprung. 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. Jede Quelle wird vom Rest des Webs isoliert, sodass Entwickler eine sichere Sandbox zum Entwickeln und Testen haben. Theoretisch ist das absolut genial. In der Praxis haben Angreifer clevere Möglichkeiten gefunden, das System zu unterwandern.

Bei Cross-Site-Scripting-Angriffen (XSS) wird beispielsweise die Richtlinie zum gleichen Ursprung umgangen, indem eine Website dazu gebracht wird, schädlichen Code zusammen mit den beabsichtigten Inhalten zu senden. Das ist ein großes Problem, da Browser allen Code, der auf einer Seite angezeigt wird, als legitimen Teil des Sicherheitsursprungs dieser Seite vertrauen. Das XSS-Cheatsheet ist ein alter, aber repräsentativer Querschnitt der Methoden, mit denen Angreifer dieses Vertrauen durch Einschleusen von schädlichem Code missbrauchen können. Wenn ein Angreifer irgendeinen Code einschleust, ist es so gut wie vorbei: Nutzersitzungsdaten werden manipuliert und Informationen, die geheim gehalten werden sollten, werden an die Bösen gesendet. Das möchten wir natürlich nach Möglichkeit vermeiden.

In dieser Übersicht wird eine Abwehrmaßnahme 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

  • Mithilfe von Zulassungslisten können Sie dem Client mitteilen, was zulässig ist und was nicht.
  • Hier finden Sie Informationen zu den verfügbaren Richtlinien.
  • Erkundigen Sie sich nach den Keywords, die sie akzeptieren.
  • 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. Die Google +1-Schaltfläche unten auf dieser Seite lädt beispielsweise Code von https://apis.google.com/js/plusone.js im Kontext der Quelle dieser Seite und führt ihn aus. Wir vertrauen diesem Code, aber wir können nicht erwarten, dass der Browser selbst herausfindet, dass Code von apis.google.com großartig ist, während Code von apis.evil.example.com wahrscheinlich nicht so gut ist. Der Browser lädt und führt jeden Code herunter, den eine Seite anfordert, unabhängig von der Quelle.

Anstatt alles, was ein Server bereitstellt, als vertrauenswürdig einzustufen, wird über die CSP der HTTP-Header Content-Security-Policy definiert, mit dem Sie eine Zulassungsliste mit vertrauenswürdigen Inhalten erstellen können. So erhält der Browser die Anweisung, 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 davon ausgehen, dass apis.google.com gültigen Code liefert, und wir uns selbst auch vertrauen, definieren wir eine Richtlinie, die die Ausführung von Scripts nur dann zulässt, wenn sie aus einer dieser beiden Quellen stammen:

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

Wie Sie wahrscheinlich schon vermutet haben, ist script-src eine Anweisung, mit der eine Reihe von scriptbezogenen Berechtigungen für eine bestimmte Seite gesteuert wird. Wir haben 'self' als gültige Skriptquelle und https://apis.google.com als eine weitere angegeben. Der Browser lädt JavaScript 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 Script aus einer anderen Quelle zu laden. Wenn es einem cleveren Angreifer gelingt, Code in Ihre Website einzuschleusen, wird er statt des erwarteten Erfolgs mit einer Fehlermeldung konfrontiert.

Die Richtlinie gilt für eine Vielzahl von Ressourcen

Scriptressourcen sind zwar die offensichtlichsten Sicherheitsrisiken, aber CSP bietet eine Vielzahl von Richtlinien, mit denen die Ressourcen, die auf einer Seite geladen werden dürfen, ziemlich genau gesteuert werden können. Da Sie script-src bereits kennen, sollte Ihnen das Konzept bereits klar sein.

Sehen wir uns kurz die restlichen Ressourcenrichtlinien an. Die folgende Liste zeigt den Status der Anweisungen auf Ebene 2. Eine Spezifikation für Level 3 wurde veröffentlicht, ist aber in den gängigen Browsern weitgehend nicht implementiert.

  • Mit base-uri werden die URLs eingeschränkt, die im <base>-Element einer Seite erscheinen können.
  • Unter child-src sind die URLs für Worker und eingebettete Frame-Inhalte aufgeführt. Beispiel: Mit child-src https://youtube.com können Videos von YouTube, aber nicht von anderen Quellen eingebettet werden.
  • connect-src schränkt die Ursprünge ein, zu denen Sie eine Verbindung herstellen können (über XHR, WebSockets und EventSource).
  • Mit font-src werden die Ursprünge angegeben, von denen Webschriften bereitgestellt werden können. Die Webschriften 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.
  • Mit frame-ancestors werden die Quellen angegeben, 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. Ist das nicht der Fall, wird wie bisher auf child-src zurückgegriffen.
  • img-src definiert die Ursprünge, aus denen Bilder geladen werden können.
  • Mit media-src werden die Ursprünge eingeschränkt, die für die Bereitstellung von Video und Audio zulässig sind.
  • Mit object-src können Sie Flash und andere Plug-ins steuern.
  • Mit plugin-types können Sie einschränken, welche Arten von Plug-ins auf einer Seite aufgerufen werden dürfen.
  • report-uri gibt eine URL an, an die ein Browser Berichte sendet, wenn ein Verstoß gegen eine Content Security Policy vorliegt. Diese Direktive kann nicht in <meta>-Tags verwendet werden.
  • style-src ist das Pendant von script-src für Stylesheets.
  • upgrade-insecure-requests weist User-Agents an, URL-Schemas umzuschreiben und HTTP in HTTPS zu ändern. Diese Richtlinie gilt für Websites mit einer großen Anzahl alter URLs, die umgeschrieben werden müssen.
  • worker-src ist eine CSP-Richtlinie der 3. Ebene, die die URLs einschränkt, die als Worker, freigegebener Worker oder Dienst-Worker geladen werden können. Stand Juli 2017 gibt es nur wenige Implementierungen dieser Richtlinie.

Standardmäßig sind Richtlinien 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 beispielsweise Schriftarten von überall aus ohne Einschränkung laden.

Sie können dieses Standardverhalten überschreiben, indem Sie eine default-src-Richtlinie angeben. Mit dieser Anweisung werden die Standardwerte für die meisten Anweisungen definiert, die Sie nicht angeben. Generell 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. In unseren früheren Beispielen haben wir nur script-src angegeben. Das bedeutet, dass Bilder, Schriftarten usw. von jeder Quelle geladen werden können.

Bei den folgenden Anweisungen wird default-src nicht als Fallback verwendet. Denken Sie daran, dass das Nichtfestlegen von Regeln dem Zulassen von allem entspricht.

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

Sie können so viele oder so wenige dieser Anweisungen verwenden, wie für Ihre spezifische Anwendung sinnvoll ist. Listen Sie sie einfach im HTTP-Header auf und trennen Sie die Anweisungen durch Semikolons. Geben Sie alle erforderlichen Ressourcen eines bestimmten Typs in einer einzelnen Richtlinie an. Wenn Sie beispielsweise script-src https://host1.com; script-src https://host2.com eingeben, wird die zweite Anweisung einfach ignoriert. Mit einem Beispiel wie dem folgenden werden beide Ursprünge korrekt als gültig angegeben:

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 geframeten Inhalte oder Plug-ins benötigen, könnte Ihre Richtlinie so aussehen:

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

Implementierungsdetails

X-WebKit-CSP- und X-Content-Security-Policy-Header werden in verschiedenen Webanleitungen verwendet. Ignorieren Sie diese Prefix-Header in Zukunft. Moderne Browser (mit Ausnahme von IE) unterstützen den Header Content-Security-Policy ohne Präfix. Diese Überschrift sollten Sie verwenden.

Unabhängig vom verwendeten Header wird die Richtlinie auf Seitenebene definiert: Sie müssen den HTTP-Header mit jeder Antwort senden, die geschützt werden soll. Das bietet eine große Flexibilität, da Sie die Richtlinie für bestimmte Seiten an ihre spezifischen Anforderungen anpassen können. Vielleicht gibt es auf einigen Seiten Ihrer Website eine Schaltfläche „+1“, auf anderen aber nicht. In diesem Fall können Sie festlegen, dass der Code für die Schaltfläche nur bei Bedarf geladen wird.

Die Quellenliste in jeder Richtlinie ist flexibel. Sie können Quellen nach Schema (data:, https:) oder nach Spezifität angeben, z. B. nur nach Hostnamen (example.com, entspricht jedem Ursprung auf diesem Host: beliebiges Schema, beliebiger Port) oder nach einem vollständig qualifizierten URI (https://example.com:443, entspricht nur HTTPS, nur example.com und nur Port 443). Platzhalter sind zulässig, aber nur als Schema, Port oder an der äußersten linken Position des Hostnamens: *://*.example.com:* würde mit allen Subdomains von example.com (aber nicht mit example.com selbst) über jedes Schema und jeden Port übereinstimmen.

Die Quellenliste akzeptiert auch vier Keywords:

  • 'none' stimmt, wie zu erwarten, mit nichts überein.
  • 'self' stimmt mit dem aktuellen Ursprung überein, aber nicht mit seinen Subdomains.
  • 'unsafe-inline' unterstützt Inline-JavaScript und Inline-CSS. (Wir gehen gleich noch genauer darauf ein.)
  • 'unsafe-eval' erlaubt Text-zu-JavaScript-Mechanismen wie eval. (Wir kommen auch darauf zurück.)

Diese Keywords müssen in einfache Anführungszeichen gesetzt werden. Mit script-src 'self' (in Anführungszeichen) wird beispielsweise die Ausführung von JavaScript vom aktuellen Host autorisiert. script-src self (ohne Anführungszeichen) erlaubt JavaScript von einem Server namens „self“ (und nicht vom aktuellen Host), was wahrscheinlich nicht Ihre Absicht war.

Sandbox-Technologie

Es gibt noch eine weitere Direktive, die es wert ist, erwähnt zu werden: sandbox. Sie unterscheidet sich ein wenig von den anderen, die wir uns angesehen haben, da sie Einschränkungen für Aktionen auf der Seite und nicht für Ressourcen auf der Seite vorsieht. Wenn die sandbox-Anweisung vorhanden ist, wird die Seite so behandelt, als wäre sie in einem <iframe> mit einem sandbox-Attribut geladen worden. Das kann eine Vielzahl von Auswirkungen auf die Seite haben, z. B. die Erzwingung eines eindeutigen Ursprungs der Seite und die Verhinderung der Formulareinreichung. Alle Details zu gültigen Sandbox-Attributen finden Sie im Abschnitt „Sandboxing“ der HTML5-Spezifikation.

Das Meta-Tag

Der bevorzugte Bereitstellungsmechanismus der CSP ist ein HTTP-Header. Es kann jedoch hilfreich sein, eine Richtlinie für eine Seite direkt im Markup festzulegen. Verwenden Sie dazu 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'"
/>

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

Inline-Code gilt als schädlich

CSP basiert auf Zulassungslisten, da dies eine eindeutige Möglichkeit ist, dem Browser anzuweisen, bestimmte Ressourcen als akzeptabel zu behandeln und den Rest abzulehnen. Herkunftsbasierte Zulassungslisten lösen jedoch nicht die größte Bedrohung durch XSS-Angriffe: Inline-Script-Injection. Wenn ein Angreifer ein Script-Tag einschleusen kann, das direkt eine schädliche Nutzlast (<script>sendMyDataToEvilDotCom();</script>) enthält, hat der Browser keinen Mechanismus, um es von einem legitimen Inline-Script-Tag zu unterscheiden. CSP löst dieses Problem, indem Inline-Script vollständig verboten wird. Das ist die einzige Möglichkeit, sicherzugehen.

Dieses Verbot gilt nicht nur für Scripts, die direkt in script-Tags eingebettet sind, sondern auch für Inline-Ereignishandler und javascript:-URLs. Sie müssen den Inhalt der 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:

<!-- 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 neu geschriebene Code bietet neben der guten Kompatibilität mit CSP eine Reihe von Vorteilen. Er ist unabhängig von der Verwendung von CSP bereits eine Best Practice. Inline-JavaScript kombiniert Struktur und Verhalten auf genau die Art und Weise, wie Sie es nicht sollten. Externe Ressourcen sind für Browser leichter im Cache zu speichern, für Entwickler verständlicher und eignen sich gut für die Kompilierung und Minimierung. Sie schreiben besseren Code, wenn Sie den Code in externe Ressourcen verschieben.

Inline-Stile werden auf die gleiche Weise behandelt: Sowohl das style-Attribut als auch style-Tags sollten in externen Stylesheets zusammengefasst werden, um sich vor einer Vielzahl von erstaunlich ausgeklügelten Methoden zur Datenextraktion zu schützen, die durch CSS ermöglicht werden.

Wenn Sie ein Inline-Script und einen Inline-Stil benötigen, können Sie sie aktivieren, indem Sie 'unsafe-inline' als zulässige Quelle in einer script-src- oder style-src-Anweisung hinzufügen. Sie können auch einen Nonce oder einen Hash verwenden (siehe unten), sollten es aber besser nicht tun. Das Verbot von Inline-Scripts ist der größte Sicherheitsgewinn, den CSP bietet. Das Verbot von Inline-Styles erhöht ebenfalls die Sicherheit Ihrer Anwendung. Es ist ein wenig Aufwand erforderlich, um sicherzustellen, dass alles richtig funktioniert, nachdem der gesamte Code außerhalb der Codezeile verschoben wurde. Dieser Aufwand lohnt sich aber.

Wenn Sie es unbedingt verwenden müssen

CSP Level 2 bietet Abwärtskompatibilität für Inline-Scripts, da Sie der Zulassungsliste bestimmte Inline-Scripts entweder mit einer kryptografischen Nonce (einmalig verwendete Zahl) oder einem Hash hinzufügen können. Das ist zwar etwas umständlich, kann aber in einer Notsituation nützlich sein.

Wenn Sie ein Einmalpasswort verwenden möchten, geben Sie Ihrem Script-Tag das Attribut „nonce“ hinzu. 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'

Nonce-Werte müssen für jede Seitenanfrage neu generiert werden und dürfen nicht erraten werden können.

Hashes funktionieren in etwa auf die gleiche Weise. Anstatt dem Script-Tag Code hinzuzufügen, erstellen Sie einen SHA-Hash des Scripts 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 Punkte zu beachten. Das Präfix sha*- gibt den Algorithmus an, der den Hash generiert. Im obigen Beispiel wird sha256- verwendet. Der CSP unterstützt auch sha384- und sha512-. Fügen Sie beim Generieren des Hashwerts keine <script>-Tags hinzu. Auch Großschreibung und Leerzeichen sind wichtig, einschließlich voran- und nachgestellter Leerzeichen.

Wenn Sie in Google nach dem Generieren von SHA-Hashes suchen, finden Sie Lösungen in einer Vielzahl von Sprachen. In Chrome 40 und höher können Sie die Entwicklertools öffnen und dann die Seite neu laden. Der Tab „Console“ enthält Fehlermeldungen mit dem richtigen SHA256-Hash für jedes Inline-Script.

Eval auch

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(), new Function() , setTimeout([string], ...) und setInterval([string], ...) sind alle Vektoren, über die eingefügter Text zu einer unerwarteten schädlichen Ausführung fü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 die integrierte JSON.parse parsen und nicht auf eval zurückgreifen. Native JSON-Vorgänge sind in allen Browsern seit IE8 verfügbar und absolut sicher.
  • Ersetzen Sie alle setTimeout- oder setInterval-Aufrufe, die Sie derzeit ausführen, durch Inline-Funktionen anstelle von Strings. Beispiel:
setTimeout("document.querySelector('a').style.display = 'none';", 10);

sollte besser so geschrieben werden:

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 zur Laufzeit zu beschleunigen. Das ist eine praktische Anwendung der dynamischen Programmierung, birgt aber das Risiko, schädlichen Text zu bewerten. Einige Frameworks unterstützen CSP standardmäßig und greifen bei fehlender eval auf einen robusten Parser zurück. Die ng-csp-Richtlinie von AngularJS ist ein gutes Beispiel dafür.

Eine bessere Wahl wäre jedoch eine Vorlagensprache, die eine Vorkompilierung bietet (z. B. Handlebars). Wenn Sie Ihre Vorlagen vorkompilieren, kann die Nutzererfahrung sogar schneller sein als bei der schnellsten Laufzeitimplementierung. Außerdem ist sie sicherer. Wenn eval und seine Text-zu-JavaScript-Geschwister für Ihre Anwendung unerlässlich sind, können Sie sie aktivieren, indem Sie 'unsafe-eval' als zulässige Quelle in einer script-src-Richtlinie hinzufügen. Wir raten jedoch dringend davon ab. Wenn die Ausführung von Strings verboten ist, wird es für Angreifer viel schwieriger, nicht autorisierten Code auf Ihrer Website auszuführen.

Berichte

Die Möglichkeit von CSPs, nicht vertrauenswürdige Ressourcen clientseitig zu blockieren, ist ein großer Vorteil für Ihre Nutzer. Es wäre jedoch sehr hilfreich, wenn eine Art Benachrichtigung an den Server gesendet würde, damit Sie alle Fehler identifizieren und beheben können, die eine schädliche Injection überhaupt erst ermöglichen. Dazu können Sie den Browser anweisen, POST-Verstoßberichte im JSON-Format an einen in einer report-uri-Richtlinie 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, die Ihnen helfen, die genaue Ursache des Verstoßes zu ermitteln, einschließlich der Seite, auf der der Verstoß aufgetreten ist (document-uri), des Verweis-URLs dieser Seite (im Gegensatz zum HTTP-Header-Feld ist der Schlüssel nicht falsch geschrieben), der Ressource, die gegen die Richtlinie der Seite verstößt (blocked-uri), der spezifischen Richtlinie, gegen die verstoßen wurde (violated-directive) und der vollständigen Richtlinie für die Seite (original-policy).

Nur Berichterstellung

Wenn Sie gerade erst mit CSP beginnen, sollten Sie den aktuellen Status Ihrer Anwendung bewerten, bevor Sie eine strenge Richtlinie für Ihre Nutzer einführen. Als Schritt auf dem Weg zu einer vollständigen Bereitstellung können Sie den Browser bitten, eine Richtlinie zu überwachen und Verstöße zu melden, die Einschränkungen jedoch nicht 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 Modus „Nur melden“ angegebene Richtlinie blockiert eingeschränkte Ressourcen nicht, sendet aber Verstoßberichte an den angegebenen Speicherort. Sie können sogar beide Header senden, um eine Richtlinie durchzusetzen und gleichzeitig eine andere zu überwachen. 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.

Praxisbeispiele

CSP 1 ist in Chrome, Safari und Firefox recht gut nutzbar, wird aber in IE 10 nur sehr eingeschränkt unterstützt. Weitere Informationen finden Sie unter caniuse.com. CSP-Level 2 ist seit Chrome-Version 40 verfügbar. Große Websites wie Twitter und Facebook haben die Kopfzeile bereits implementiert (die Fallstudie von Twitter ist lesenswert). Der Standard ist also bereit, auf Ihren eigenen Websites implementiert zu werden.

Der erste Schritt zum Erstellen einer Richtlinie für Ihre Anwendung besteht darin, die Ressourcen zu bewerten, die Sie tatsächlich laden. Sobald Sie der Meinung sind, dass Sie die Funktionsweise Ihrer App verstanden haben, können Sie eine Richtlinie basierend auf diesen Anforderungen einrichten. Sehen wir uns einige häufige Anwendungsfälle an und überlegen, wie wir sie innerhalb der Schutzmaßnahmen der CSP am besten unterstützen können.

Anwendungsfall 1: Widgets für soziale Medien

  • 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 minimale Richtlinie 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 kopiert werden. Wenn Sie eine Level-1-Richtlinie mit frame-src hatten, mussten Sie sie aufgrund von Level 2 in child-src ändern. Das ist bei CSP-Level 3 nicht mehr erforderlich.

  • Die Facebook-Magie-Schaltfläche kann auf verschiedene Weise implementiert werden. Wir empfehlen, die <iframe>-Version zu verwenden, da sie sich in einer sicheren Sandbox vom Rest Ihrer Website getrennt befindet. Für die ordnungsgemäße Funktion 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 das, um HTTPS explizit anzugeben: https://facebook.com. Es gibt keinen Grund, HTTP zu verwenden, wenn es nicht nötig ist.

  • Die Tweet-Schaltfläche von Twitter benötigt Zugriff auf ein Script und einen Frame, die beide auf https://platform.twitter.com gehostet werden. Twitter stellt ebenfalls standardmäßig eine relative URL bereit. Bearbeiten Sie den Code, um HTTPS anzugeben, wenn Sie ihn lokal kopieren und 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, einfach eine default-src von 'none' festzulegen und in der Konsole zu prüfen, welche Ressourcen Sie aktivieren müssen, damit die Widgets funktionieren.

Das Einfügen mehrerer Widgets ist ganz einfach: Kombinieren Sie einfach die Richtlinienanweisungen und denken Sie daran, alle Ressourcen eines bestimmten Typs in einer einzigen Richtlinie 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: Lockdown

Angenommen, Sie betreiben eine Banking-Website und möchten dafür sorgen, dass nur die von Ihnen selbst erstellten 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, den Stil und das Script von einem CDN unter https://cdn.mybank.net und stellt über XHR eine Verbindung zu https://api.mybank.com/ her, um verschiedene Daten abzurufen. Frames werden nur für lokale Seiten der Website verwendet und nicht für die Herkunft Dritter. Auf der Website gibt es kein Flash, keine Schriftarten und keine 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 Forums für Trauringe möchte dafür sorgen, dass alle Ressourcen nur über sichere Kanäle geladen werden. Er schreibt aber nicht viel Code und ist nicht in der Lage, große Teile der Forumsoftware von Drittanbietern, die bis zum Rand mit Inline-Script und Stil gefüllt ist, neu zu schreiben. Die folgende Richtlinie ist dann wirksam:

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

Auch wenn https: in default-src angegeben ist, wird diese Quelle nicht automatisch von den Script- und Style-Direktiven übernommen. Jede Anweisung überschreibt die Standardeinstellung für diesen bestimmten Ressourcentyp vollständig.

Die Zukunft

Content Security Policy Level 2 ist eine empfohlene Option. 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 der Diskussion zu diesen anstehenden Funktionen interessiert sind, lesen Sie die Mailingliste „public-webappsec@“ oder nehmen Sie selbst daran teil.

Feedback