Content Security Policy

Mike West
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 sollte auf keinen Fall Zugriff erhalten. Jeder Ursprung wird vom Rest des Web isoliert gehalten, sodass Entwickler eine sichere Sandbox zum Erstellen und Spielen erhalten. Theoretisch ist das absolut genial. In der Praxis haben Angreifer clevere Möglichkeiten gefunden, das System zu untergraben.

Bei Cross-Site-Scripting-Angriffen (XSS) wird beispielsweise dieselbe Ursprungsrichtlinie umgangen, indem eine Website dazu verleitet wird, zusammen mit dem gewünschten Inhalt schädlichen Code bereitzustellen. Das ist ein riesiges Problem, da Browser dem gesamten Code vertrauen, der auf einer Seite als rechtmäßiger Teil des Sicherheitsherkunftsorts dieser Seite angezeigt wird. Der XSS-Cheat Sheet ist ein alter, aber repräsentativer Querschnitt der Methoden, mit denen Angreifer dieses Vertrauen durch Einschleusen von schädlichem Code verletzen könnten. Wenn ein Angreifer überhaupt irgendeinen Code einschleust, ist es so gut wie ein Spiel: Die Daten der Nutzersitzung werden kompromittiert und Informationen, die geheim gehalten werden sollten, werden an die Bad Guys exfiltriert. Das möchten wir natürlich vermeiden.

In dieser Übersicht wird eine Abwehrmaßnahme vorgestellt, 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.
  • Informieren Sie sich über die verfügbaren Anweisungen.
  • Erfahre, welche Keywords sie verwenden.
  • Inline-Code und eval() werden als schädlich eingestuft.
  • Melden Sie Richtlinienverstöße an Ihrem Server, bevor Sie sie erzwingen.

Quellen-Zulassungslisten

Das Problem, das bei XSS-Angriffen ausgenutzt wird, besteht darin, dass der Browser nicht zwischen einem Skript, das Teil Ihrer Anwendung ist, und einem Skript, das böswillig von einem Drittanbieter eingeschleust wurde, unterscheiden kann. Die Google +1-Schaltfläche unten auf dieser Seite lädt beispielsweise Code von https://apis.google.com/js/plusone.js im Kontext des Ursprungs dieser Seite und führt ihn aus. Wir vertrauen diesem Code, aber wir können nicht davon ausgehen, dass der Browser selbst erkennt, dass der Code von apis.google.com erfolgreich ist, während der Code von apis.evil.example.com wahrscheinlich nicht funktioniert. Der Browser lädt problemlos den von einer Seite angeforderten Code herunter und führt ihn aus, unabhängig von der Quelle.

Anstatt alles, was ein Server bereitstellt, zu vertrauen, definiert die CSP den Content-Security-Policy-HTTP-Header. Damit können Sie eine Zulassungsliste mit Quellen mit vertrauenswürdigen Inhalten erstellen und den Browser anweisen, nur Ressourcen aus diesen Quellen auszuführen oder zu rendern. Selbst wenn ein Angreifer ein Loch zum Einfügen des Skripts finden kann, stimmt das Skript nicht mit der Zulassungsliste überein und wird daher nicht ausgeführt.

Da wir darauf vertrauen, dass apis.google.com gültigen Code liefert, und wir dies auch selbst tun, definieren wir eine Richtlinie, die die Ausführung des Skripts nur zulässt, wenn es aus einer dieser beiden Quellen stammt:

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

Wie Sie wahrscheinlich schon vermutet haben, ist script-src eine Anweisung, die eine Reihe von skriptbezogenen Berechtigungen für eine bestimmte Seite steuert. Wir haben 'self' als gültige Skriptquelle und https://apis.google.com als andere angegeben. JavaScript wird vom Browser ordnungsgemäß über HTTPS und vom Ursprung der aktuellen Seite von apis.google.com heruntergeladen und ausgeführt.

Konsolenfehler: Das Skript "http://evil.example.com/evil.js" konnte nicht geladen werden, da es 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 ein Skript aus einer anderen Quelle zu laden. Wenn es einem cleveren Angreifer gelingt, Code in deine Website einzuschleusen, landet er kopfüber mit einer Fehlermeldung und nicht dem erwarteten Erfolg.

Richtlinie gilt für eine Vielzahl von Ressourcen

Während Skriptressourcen die offensichtlichsten Sicherheitsrisiken darstellen, bietet die CSP eine Vielzahl von Richtlinienanweisungen, mit denen sich die Ressourcen, die auf einer Seite geladen werden dürfen, recht genau steuern können. Sie haben script-src bereits gesehen, also sollte das Konzept klar definiert sein.

Gehen wir die restlichen Ressourcenanweisungen kurz durch. Die folgende Liste gibt den Status der Anweisungen auf Ebene 2 wieder. Eine Spezifikation der Stufe 3 wurde veröffentlicht, die in den gängigen Browsern jedoch fast nicht implementiert ist.

  • Mit base-uri werden die URLs eingeschränkt, die im <base>-Element einer Seite erscheinen können.
  • child-src listet die URLs für Worker und die eingebetteten Frame-Inhalte auf. Beispiel: Mit child-src https://youtube.com können Videos von YouTube eingebettet werden, 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 Ursprünge an, die Webschriftarten bereitstellen 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 über <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 Nicht-HTML-Ressourcen.
  • frame-src wurde in Ebene 2 eingestellt, wird aber in Ebene 3 wiederhergestellt. Ist er nicht vorhanden, wird wie zuvor auf child-src zurückgesetzt.
  • Mit img-src werden die Ursprünge definiert, von denen Bilder geladen werden können.
  • media-src schränkt die Quellen ein, die für die Übermittlung von Video und Audio 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 bei Verstößen gegen eine Content Security Policy Berichte sendet. Diese Anweisung kann nicht in <meta>-Tags verwendet werden.
  • style-src ist das Gegenstück von script-src zu Stylesheets.
  • upgrade-insecure-requests weist User-Agents an, URL-Schemas umzuschreiben und HTTP zu HTTPS zu ändern. Diese Anweisung ist für Websites mit einer großen Anzahl alter URLs vorgesehen, die überschrieben werden müssen.
  • worker-src ist eine CSP-Richtlinie der Stufe 3, die die URLs einschränkt, die als Worker, Shared Worker oder Service Worker geladen werden können. Seit Juli 2017 enthält diese Richtlinie eingeschränkte Implementierungen.

Anweisungen sind standardmäßig weit offen. Wenn Sie keine bestimmte Richtlinie für eine Anweisung 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 ohne Einschränkung laden.

Sie können dieses Standardverhalten überschreiben, indem Sie eine default-src-Anweisung angeben. Diese Anweisung definiert die Standardwerte für die meisten Anweisungen, die Sie nicht angeben. Dies gilt im Allgemeinen für jede Anweisung, die auf -src endet. Wenn default-src auf https://example.com gesetzt ist und keine font-src-Anweisung angegeben wird, können Sie Schriftarten ausschließlich aus https://example.com laden. In unseren vorherigen Beispielen haben wir nur script-src angegeben. Das bedeutet, dass Bilder, Schriftarten usw. von jedem Ursprung geladen werden können.

In den folgenden Anweisungen wird default-src nicht als Fallback verwendet. Wenn Sie sie nicht festlegen, bedeutet das auch, 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. Listen Sie jede Anweisung einfach im HTTP-Header auf und trennen Sie die Anweisungen durch Semikolons. Achten Sie darauf, alle erforderlichen Ressourcen eines bestimmten Typs in einer einzelnen Anweisung aufzulisten. Wenn Sie etwa script-src https://host1.com; script-src https://host2.com schreiben, wird die zweite Anweisung einfach ignoriert. In etwa so würden beide Ursprünge korrekt als gültig angegeben:

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

Wenn Sie beispielsweise eine Anwendung haben, die alle ihre 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, könnte Ihre Richtlinie so aussehen:

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

Implementierungsdetails

Die Header X-WebKit-CSP und X-Content-Security-Policy finden Sie in verschiedenen Anleitungen im Web. Diese vorangestellten Kopfzeilen sollten Sie in Zukunft ignorieren. Moderne Browser (mit Ausnahme von IE) unterstützen den Header Content-Security-Policy ohne Präfix. Diesen Header sollten Sie verwenden.

Unabhängig vom verwendeten Header wird die Richtlinie seitenweise definiert: Der HTTP-Header muss zusammen mit jeder Antwort gesendet werden, die geschützt sein soll. Dies bietet ein hohes Maß an Flexibilität, da Sie die Richtlinie für bestimmte Seiten je nach deren spezifischen Anforderungen optimieren können. Möglicherweise hat eine Gruppe von Seiten Ihrer Website eine +1-Schaltfläche und andere nicht. Sie können zulassen, dass der Schaltflächencode nur bei Bedarf geladen wird.

Die Quellenliste in jeder Anweisung ist flexibel. Sie können Quellen nach Schema (data:, https:) oder in Spezifität von nur Hostname (example.com, was jedem Ursprung auf diesem Host entspricht: ein beliebiges Schema, jeder Port) bis zu einem voll qualifizierten URI (https://example.com:443, der nur HTTPS, nur example.com und nur Port 443 entspricht) angeben. Platzhalter sind zulässig, jedoch nur als Schema, Port bzw. an der obersten Position des Hostnamens: *://*.example.com:* stimmt mit allen Subdomains von example.com überein (aber nicht example.com selbst), bei Verwendung eines beliebigen Port-Schemas.

Die Quellenliste akzeptiert auch vier Keywords:

  • 'none' stimmt erwartungsgemäß nicht überein.
  • 'self' stimmt mit dem aktuellen Ursprung überein, aber nicht mit seinen Subdomains.
  • In 'unsafe-inline' sind JavaScript- und CSS-Inline-Code zulässig. Darauf gehen wir später noch ein.
  • 'unsafe-eval' ermöglicht Text-in-JavaScript-Mechanismen wie eval. (Wir werden auch darauf eingehen.)

Für diese Keywords sind einfache Anführungszeichen erforderlich. Beispiel: script-src 'self' (mit Anführungszeichen) autorisiert die Ausführung von JavaScript vom aktuellen Host; script-src self (ohne Anführungszeichen) lässt JavaScript von einem Server namens „self“ zu (und nicht vom aktuellen Host). Dies war wahrscheinlich nicht das, was Sie gemeint haben.

Sandbox-Technologie

Es gibt noch eine weitere Anweisung, über die ich sprechen sollte: sandbox. Sie unterscheidet sich ein wenig von den anderen, die wir bereits betrachtet haben, da hier Einschränkungen für Aktionen gelten, die die Seite ausführen kann, anstatt für Ressourcen, die die Seite laden kann. Wenn die Anweisung sandbox vorhanden ist, wird die Seite so behandelt, als wäre sie in einem <iframe>-Element mit einem sandbox-Attribut geladen. Dies kann verschiedene Auswirkungen auf die Seite haben: z. B. dass die Seite zu einem eindeutigen Ursprung gezwungen wird oder das Senden von Formularen verhindert wird. Dies würde den Rahmen dieses Artikels sprengen, aber alle Einzelheiten zu gültigen Sandbox-Attributen finden Sie in der HTML5-Spezifikation im Abschnitt „Sandboxing“.

Das Meta-Tag

Der bevorzugte Übermittlungsmechanismus der CSP ist ein HTTP-Header. Es kann jedoch sinnvoll sein, direkt im Markup eine Richtlinie auf einer Seite festzulegen. Dazu verwenden Sie 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 deutlich werden, dass die CSP auf Zulassungslisten basiert, da dies eine eindeutige Methode ist, den Browser anzuweisen, bestimmte Gruppen von Ressourcen als akzeptabel zu behandeln und den Rest abzulehnen. Ursprungsbasierte Zulassungslisten lösen jedoch nicht die größte Bedrohung durch XSS-Angriffe, nämlich die Inline-Script-Einschleusung. Wenn ein Angreifer ein Skript-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-Skript-Tag zu unterscheiden. Die CSP löst dieses Problem, indem sie Inline-Skripts vollständig sperrt. Dies ist die einzige Möglichkeit, sich zu vergewissern.

Dieses Verbot umfasst nicht nur direkt in script-Tags eingebettete Skripts, sondern auch Inline-Event-Handler und javascript:-URLs. Sie müssen den Inhalt von script-Tags in eine externe Datei verschieben und javascript:-URLs sowie <a ... onclick="[JAVASCRIPT]"> durch entsprechende addEventListener()-Aufrufe ersetzen. Sie können beispielsweise Folgendes umschreiben:

<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 der CSP hinausgehen. Er ist unabhängig von der Verwendung der CSP bereits eine Best Practice. Inline-JavaScript vermischt Struktur und Verhalten auf die Art und Weise, wie Sie es nicht vermeiden sollten. Externe Ressourcen können für Browser einfacher im Cache gespeichert werden, sind für Entwickler verständlicher und eignen sich für Kompilierung und Kompilierung. Sie schreiben besseren Code, wenn Sie sich die Mühe machen, Code in externe Ressourcen zu verschieben.

Der Inline-Stil wird auf dieselbe Weise behandelt: Sowohl das style-Attribut als auch das style-Tag sollten in externen Stylesheets zusammengefasst werden, um eine Vielzahl von überraschenderweise cleveren Daten-Exfiltrationsmethoden zu schützen, die CSS unterstützen.

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), was aber nicht unbedingt der Fall sein sollte. Das Verbot von Inline-Skripts ist der größte Sicherheitsgewinn, den die CSP bietet, und das Verbot des Inline-Stils härtet Ihre Anwendung ebenfalls. Sie müssen im Vorfeld etwas aufwändig sein, damit alles wie vorgesehen funktioniert, nachdem Sie den gesamten Code außer Betrieb gesetzt haben. Aber das ist ein Kompromiss, der sich auf jeden Fall lohnt.

Wenn Sie es unbedingt verwenden müssen,

CSP Level 2 bietet Abwärtskompatibilität für Inline-Skripts. Sie können der Zulassungsliste dann entweder mit einer kryptografischen Nonce (einmalig verwendete Nummer) oder einem Hash bestimmte Inline-Skripts hinzufügen. Das mag mühsam sein, ist aber im Zweifelsfall nützlich.

Um eine Nonce zu verwenden, weisen Sie Ihrem Skript-Tag ein Nonce-Attribut zu. 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 in die script-src-Anweisung ein und hängen Sie an das nonce--Keyword an.

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

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

Hashes funktionieren ähnlich. Statt Code in das Skript-Tag einzufügen, erstellen Sie einen SHA-Hash-Wert des Skripts selbst und fügen ihn der Anweisung script-src hinzu. Angenommen, 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 gibt es einige Dinge zu beachten. Das Präfix sha*- gibt den Algorithmus an, der den Hash generiert. Im Beispiel oben wird sha256- verwendet. Die CSP unterstützt auch sha384- und sha512-. Fügen Sie beim Generieren des Hashs nicht die <script>-Tags ein. Auch Groß- und Kleinschreibung sowie Leerzeichen am Anfang oder Ende werden berücksichtigt.

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

Auch Bewertung

Selbst wenn ein Angreifer Skripte nicht direkt einschleusen kann, ist er in der Lage, Ihre Anwendung dazu zu bringen, ansonsten inaktiven Text in ausführbares JavaScript zu konvertieren und für ihn auszuführen. eval(), new Function() , setTimeout([string], ...) und setInterval([string], ...) sind Vektoren, über die injizierter Text etwas unerwartet schädliches Ergebnis ausführen kann. Die Standardreaktion der CSP auf dieses Risiko besteht darin, alle diese Vektoren vollständig zu blockieren.

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

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

wäre besser so geschrieben:

setTimeout(function () {
  document.querySelector('a').style.display = 'none';
}, 10);
  • Vermeiden Sie Inline-Vorlagen zur Laufzeit: Viele Vorlagenbibliotheken verwenden new Function() großflächig, um die Vorlagengenerierung während der Laufzeit zu beschleunigen. Es ist eine raffinierte Anwendung dynamischer Programmierung, birgt jedoch auch das Risiko, schädlichen Text zu bewerten. Einige Frameworks unterstützen die vorkonfigurierte CSP und wechseln ohne eval auf einen robusten Parser. Die Anweisung ng-csp von AngularJS ist ein gutes Beispiel dafür.

Allerdings wäre eine Vorlagensprache, die eine Vorkompilierung ermöglicht (z. B. Handlebars), die bessere Wahl. Das Vorkompilieren Ihrer Vorlagen kann die Nutzererfahrung noch schneller machen als die schnellste Laufzeitimplementierung und ist außerdem sicherer. Wenn eval und seine Text-zu-JavaScript-Brethren für Ihre Anwendung unerlässlich sind, können Sie sie aktivieren, indem Sie 'unsafe-eval' als zulässige Quelle in eine script-src-Anweisung einfügen. Wir raten jedoch dringend davon ab. Wenn Sie die Funktion zum Ausführen von Strings sperren, erschweren Sie es Angreifern, nicht autorisierten Code auf Ihrer Website auszuführen.

Berichte

Die Fähigkeit der 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 zurückzusenden, damit Sie Fehler identifizieren und beheben können, die eine schädliche Injektion ermöglichen. Zu diesem Zweck können Sie den Browser anweisen, POST Verstoßberichte im JSON-Format an einen Speicherort zu senden, der in einer report-uri-Anweisung angegeben ist.

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"
  }
}

Hier finden Sie eine große Menge an Informationen, mit denen Sie die genaue Ursache des Verstoßes ermitteln können. Dazu gehören die Seite, auf der der Verstoß aufgetreten ist (document-uri), die Referrer-URL der Seite (beachten Sie, dass der Schlüssel im Gegensatz zum HTTP-Header-Feld nicht falsch geschrieben ist), die Ressource, die gegen die Richtlinie der Seite (blocked-uri) verstoßen hat, 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 der CSP beginnen, ist es sinnvoll, den aktuellen Status Ihrer Anwendung zu prüfen, bevor Sie eine drakonische Richtlinie für Ihre Nutzer einführen. Als Sprungbrett für eine vollständige Bereitstellung können Sie den Browser bitten, eine Richtlinie zu überwachen, Verstöße melden, aber die Einschränkungen nicht erzwingen. 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 Nur-Bericht-Modus angegebene Richtlinie blockiert keine eingeschränkten Ressourcen. Es werden jedoch Berichte zu Verstößen an den von Ihnen angegebenen Standort gesendet. Sie können sogar beide Header senden und so eine Richtlinie erzwingen, während Sie eine andere überwachen. So lassen sich die Auswirkungen von Änderungen an der CSP Ihrer Anwendung hervorragend bewerten: Aktivieren Sie die Berichterstellung für eine neue Richtlinie, beobachten Sie die Berichte zu Verstößen und beheben Sie etwaige Fehler. Wenn Sie mit den Auswirkungen zufrieden sind, können Sie mit der Durchsetzung der neuen Richtlinie beginnen.

Nutzung in der Praxis

CSP 1 kann in Chrome, Safari und Firefox verwendet werden, in IE 10 wird sie jedoch nur eingeschränkt unterstützt. Weitere Informationen finden Sie unter caniuse.com. CSP-Level 2 ist seit Version 40 in Chrome verfügbar. Der Header wurde auf riesigen Websites wie Twitter und Facebook bereitgestellt (die Fallstudie von Twitter ist eine Lektüre wert), und der Standard ist sehr bereit, um mit der Bereitstellung auf Ihren eigenen Websites zu beginnen.

Wenn Sie eine Richtlinie für Ihre Anwendung erstellen möchten, müssen Sie zuerst die Ressourcen bewerten, die Sie tatsächlich laden. Wenn Sie der Meinung sind, dass Sie wissen, wie die Elemente in Ihrer App zusammengesetzt sind, richten Sie auf der Grundlage dieser Anforderungen eine Richtlinie ein. Sehen wir uns einige gängige Anwendungsfälle an und überlegen wir, wie wir sie im Rahmen der Schutzmaßnahmen der CSP am besten unterstützen können.

Anwendungsfall 1: Social-Media-Widgets

  • Die +1-Schaltfläche von Google enthält ein Skript von https://apis.google.com und bettet ein <iframe> von https://plusone.google.com ein. Sie benötigen eine Richtlinie, die diese beiden 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 extrahiert werden. Wenn Sie eine auf Ebene 1 basierende Richtlinie mit frame-src hatten, mussten Sie sie gemäß Stufe 2 zu child-src ändern. Dies ist in CSP Level 3 nicht mehr erforderlich.

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

  • Die Tweet-Schaltfläche von Twitter erfordert den Zugriff auf ein Skript und einen Frame, die beide unter 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/einfügen. Wenn du das von Twitter bereitgestellte JavaScript-Snippet in eine externe JavaScript-Datei verschiebst, ist script-src https://platform.twitter.com; child-src https://platform.twitter.com einsatzbereit.

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

Das Einbinden mehrerer Widgets ist unkompliziert: Kombinieren Sie einfach die Richtlinienanweisungen und denken Sie daran, alle Ressourcen eines einzelnen Typs zu einer einzigen Anweisung zusammenzuführen. Wenn Sie alle drei Social-Media-Widgets verwenden möchten, würde die Richtlinie so 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

Angenommen, Sie betreiben eine Banking-Website und möchten sicherstellen, 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, Stile und Skripts aus einem CDN in https://cdn.mybank.net und stellt über XHR eine Verbindung zu https://api.mybank.com/ her, um verschiedene Datenbits abzurufen. Frames werden verwendet, aber nur für Seiten, die sich auf der Website befinden (keine Quellen von Drittanbietern). Es gibt kein Flash auf der Website, keine Schriftarten, keine Extras. Der restriktivste CSP-Header, den wir senden können, 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 viel Code. Das Umschreiben großer Teile der Drittanbieter-Forumssoftware, die bis zum Rand mit Inline-Skript und Stil gefüllt ist, wäre ungeklärt. In diesem Fall gilt die folgende Richtlinie:

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 die Standardeinstellung für diesen bestimmten Ressourcentyp vollständig.

Die Zukunft

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

Wenn Sie an einer Diskussion zu diesen neuen Funktionen interessiert sind, überfliegen Sie die Archive von public-webappsec@ oder nehmen Sie selbst teil.

Feedback