CSP - mehr Sicherheit fürs Web

Permalink

Ausgangsproblem

Ein Problem im Web entsteht durch die Nutzung von Ressourcen verschiedener Herkunft. Was eigentlich eine der Stärken des Netzes ist, Ressourcen verschiedenster Art und Herkunft zu verknüpfen, eröffnet auch Gefahrenquellen. Insbesondere im Umgang mit User-Generated-Content tritt dies immer wieder zutage. Findige Angreifer finden immer wieder einen Weg Schadcode zur Ausführung zu bringen. SQL-Injection, Cross-Site-Scripting und andere Angriffsvektoren funktionieren weil Code in einer fremden Anwendung oder Webseite eingeschleust werden konnte. Ein anderes Beispiel ist der Android-Bug Stagefright. Hierbei wird eine manipulierte Videodatei genutzt um in Android einzubrechen.

Problemlösung

Mit der Content Security Policy versucht das W3C das Problem abzumildern. Dazu kann der Entwickler für verschiedene Arten von Ressourcen oder Zugriffstechniken definieren welche Quellen als Vertrauenswürdig gelten. URLs anderer Quellen sollen vom Browser dann gar nicht erst geladen werden.

Gefahrenquellen

Im aktuellen Entwurf des CSP Level 2 identifiziert die Spezifikation im folgenden aufgeführten Arten von Ressourcen. Für jede dieser Arten ist eine Direktive definiert unter der die erlaubten Quellen aufgeführt werden können:

  • Scripte (script-src)
  • Stylesheets (style-src)
  • Bilder (img-src)
  • Schriften (font-src)
  • Video und Audio (media-src)
  • Formulare (form-action)
  • Scriptgesteuerte Netzwerkzugriffe wie Ajax-Requests (connect-src)
  • Inhalte von object-, embed- oder applet-Elementen (object-src)
  • Plugins (plugin-types)
  • Eingebettete Inhalte (child-src)
  • Einbettende Seiten (frame-ancestors)

URL-Masken

Für alle diese Direktiven, außer plugin-types, kann man eine Liste von URL-Masken angeben die dann als vertrauenswürdig gelten. In diesen URL-Masken, bestehend aus Protokoll, Hostname, Port und Pfad. Jeder Teil kann weggelassen werde, das bedeutet dann ‘jedes Protokoll’ beziehungsweise Hostname, Port oder Pfad. Der Host kann generalisiert werden durch einen *.

Hier einige Beipiele:

  • https: – nur HTTPS-Ressourcen
  • human-injection.de – nur Ressourcen von human-injection.de
  • *.human-injection.de – nur Ressourcen von Subdomains unterhalb von human-injection.de
  • *:443 – alle Ressourcen über Port 443
  • https://*.de:443 – alle Ressourcen aus HTTPS-Quellen unterhalb der deutschen TLD über Port 443
  • http://human-injection.de:80/Home – nur die angegebene URL

Der Stern (*) kann nur in Zusammenhang mit Domainnamen verwendet werden. Alleine verwendet bedeutet er: Jede Domain in Kombination mit jedem Protokoll, jedem Port und jedem Pfad. Diese Beschränkung auf Host- oder Domainnamen hat einige überraschende Auswirkungen. Durch die Verwendung des Asterisk werden nämlich Protokolle wie file://, data:// oder blob:// nicht erfasst da sie sich nicht auf Hostnamen beziehen. Diese Protokolle müssen daher zusätzlich angegeben werden wenn Sie benötigt werden.

Mozilla hat übrigens vor Version 40 des Firefox diese Regel nicht beachtet und das Verhalten nachträglich in Ihrem Browser angepasst, was bei bei meinem Podcatcher zu hübschen Fehlern geführt hat.

Plugins und eingebettete Inhalte

Im Gegensatz zu anderen Direktiven schränkt plugin-types nicht die Quelle ein sondern die Dateiformate die wiedergegeben werden können. Die Werte sind demzufolge auch nicht URL-Masken sondern MIME-Types. Mittels der Angabe application/pdf werden etwa PDF-Dokumente für das Einbetten zugelassen, aber alle anderen eingebetteten Inhalte nicht geladen.

Wenn man die Inhalte auch nach ihrer Quelle filtern will kann man dafür die Direktive object-src zusätzlich nutzen.

Keywords

Zusätzlich zu den URL-Masken lassen sich auch vier Schlüsselwörter verwenden.

Mit ‘none’ (inklusive der Anführungszeichen) werden alle Quellen für die verwendete Direktive abgewiesen. Auf alle Ressourcen von der Domain der Webseite schränkt hingegen das Keyword ‘self’ ein.

Für Scripte und Stylesheets gibt es noch zwei weitere Schlüsselwörter. Die Nutzung der entsprechenden CSP-Direktiven führt dazu das auch Inline-Scripte beziehungsweise -Styles nicht angewendet werden. Mit ‘unsafe-inline’ schaltet man dieses verhalten wider ab. Allerdings sind Inline-Scripte ein großes Einfallstor für Angreifer, man sollte dieses Keyword also mit bedacht einsetzen.

Das andere Schlüsselwort ‘unsafe-eval’ erlaubt den Einsatz der eval-Funktion in Javascript. Auch hier sollte man sich genau überlegen was man tut.

Default-Direktive

Um nicht alle elf oben aufgeführten Direktiven einzeln konfigurieren zu müssen gibt es auch noch die Direktive default-src. Damit lassen sich die Direktiven child-src, connect-src, font-src, img-src, media-src, object-src, script-src, style-src zusammenfassen.

Mitteilungsbedürftig

Nach all den bisherigen Ausführungen über Direktiven bleibt die Frage wie diese überhaupt den Browser erreichen? Normalerweise verwendet man dazu den HTTP-Header Content-Security-Policy. Als Wert dieses Headers verwendet man, durch Semikolon getrennt, die Direktiven.

In Webserver Apache kann man den Header am einfachsten über die htaccess-Datei einfügen:

set Content-Security-Policy "default-src 'self'; img-src: img.human-injection.de" 

Alternativ kann man auch ein HTML-Meta-Tag verwenden, das ist aber nur zweite Wahl:

<meta http-equiv="Content-Security-Policy" content="script-src 'self'; img-src: img.human-injection.de">

Und sonst?

Anstelle des Blockierens von Ressourcen kann man auch auf ein Reporting ausweichen. Dazu verwendet man den HTTP-Header Content-Security-Policy-Report-Only mit den selben Werten wie oben und einer Report-URL zusätzlich. An diese URL wird im Fall eines Verstoßes gegen die CSP ein JSON-Bericht geschickt.

Content-Security-Policy-Report-Only:  "default-src 'self'; img-src: img.human-injection.de; report-uri http://human-injection.de/csp.report"

Wenn man seine Seite testen möchte bietet sich SecurityHeader.io an. Hier bekommt man auch gleich noch ein paar andere Tipps.