Digitale Selbstverteidigung

Mehr Sicherheit auf der eigenen Website

Warum sollten wir uns überhaupt mit Sicherheit beschäftigen?

An Daten hängen ganze (digitale) Existenzen

  • Das selbe Passwort wird oft für verschiedene Dienste verwendet
  • Viele Leute führen und teilen ihr Leben mittlerweile online: persönliche Informationen, Online-Profile, Adressen, Kontakte und Freunde, Kreditkarten/Bankdaten, persönliche Fotos, Texte, Gefühle.

Doch der wichtigste Grund ist:

  • Ihr fragt eure Nutzer nach all diesen Daten …
  • … um Dienstleistungen anzubieten, für Marketing-Zwecke, etc.
  • Eure Nutzer vertrauen euch.
  • Deshalb ist es eure Pflicht, sorgsam damit umzugehen.

Zwei Beispiele für typische Website-Sicherheitsprobleme

Clickjacking

„Entführen“ von Mausklicks auf eine andere Seite

Angriffsziel

Angreifende Website

Was passiert hier?

Der Angreifer bindet die Seite in ein absolut positioniertes Iframe ein:


iframe {
    width: 850px;
    height: 370px;
    position: absolute;
    top: -198px;
    left: -424px;

    /* Nur zur Demonstration auf 50% gesetzt. */
    filter: alpha(opacity=50);
    opacity: 0.5;
}
                    

Die selbe Seite. Transparenz des Iframes auf 0 gesetzt.

Mögliche Angriffszenarien

  • Ändern von Privatsphäre-Einstellungen
  • Löschen von Accounts oder Daten
  • Auslösen von 1-Klick-Bestellungen, o.ä.

 
Auch mehrstufige Prozesse (z.B. Bestätigunsdialoge)
können so abgefangen werden.

Abhilfe: X-Frame-Options (HTTP-Header)

  • X-Frame-Options: SAMEORIGIN
    Same-Origin-Policy: Protokoll (z.B. http://) und (Sub)Domain muss identisch sein
  • X-Frame-Options: DENY
    Unterbindet das Einbetten der Seite vollständig
  • X-Frame-Options: ALLOW-FROM origin
    Einbetten ausschließlich von einem bestimmten Ziel aus (z.B. http://www.example.com)

    Nur in Firefox 18+/IE9+, wird künftig anders gelöst

Browser-Support X-Frame-Options (DENY/SAMEORIGIN)

  • Chrome 4.1+
  • Firefox 3.6.9
  • Safari 4+
  • Internet Explorer 8+
  • Opera 10.50+

HTTP-Header in Apache setzen

.htaccess oder Server-Konfiguration

                        
<IfModule mod_headers.c>
    Header always set X-Frame-Options "SAMEORIGIN"
</IfModule>
                        
                    

HTTP-Header im IIS setzen

web.config

                        
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <httpProtocol>
            <customHeaders>
                <add name="X-Frame-Options" value="SAMEORIGIN"/>
            </customHeaders>
        </httpProtocol>
    </system.webServer>
</configuration>
                        
                    

Cross Site Scripting (XSS)

Ungewolltes Ausführen von fremden JavaScript-Code

<script>alert(1)</script>

Wenn es gelingt, diesen Beispielcode auszuführen, kann
jeder beliebige JavaScript-Code ausgeführt werden

Reflected XSS-Attacken kommen meist von anderen Seiten:

http://example.com/search.php?q=<script>alert(1)</script>

Beispiel für eine DOM XSS-Attacke


Der Text des Suchfelds wird in der Seite ausgegeben. Auch <script>alert(1)</script>

Stored XSS-Attacken werden auf dem Server gespeichert
und an jeden Besucher ausgeliefert.

Wie sehen XSS-Angriffsvektoren aus?

(Lediglich ein sehr kleiner Auszug)

(Quelle: HTML5 Security Cheatsheet)

<​frameset onload=alert(1)>
<​body oninput=alert(1)><​input autofocus>
<​video poster=javascript:alert(1)//></video>
<!--<img src="--><​img src=x onerror=alert(1)//">
<​img[a][b]src=x[d]onerror[c]=[e]"alert(1)">

Wie lassen sich XSS-Angriffe minimieren?

  • Alle Eingaben des Users genau validieren
  • Nicht nur Formulare, sondern auch z.B. GET-Parameter beachten
  • XSS-Code kann auch über Seitenkanäle eingeschleust werden
    (z.B. SQL-Injection)
  • Auf Eingabemöglichkeit von HTML am besten verzichten

/Everybody stand back/

I know Regular Expressions!

XKCD #208

Filtern mit Regulären Ausdrücken

/<[^>]*>?/g filtert alle HTML-Tags aus.


  • … aber leider auch a < b
  • Man verändert also eventuell den Inhalt
  • Andere Repräsentationen von < und > bleiben erhalten, z.B.:
    &lt; &gt; %3C %3E


Diese Lösung kann sehr hilfreich sein, ist aber nicht 100%ig perfekt.

Was ist, wenn man auf HTML-Eingabe nicht verzichten kann?

Idee #1:
<script>, onload, onerror, etc. herausfiltern

Leider keine gute Idee:

<scr<script>ipt>alert(1)
</sc<script>ri<script>pt>
                    

Idee #2:
Filtern von HTML in JavaScript

As seen many times on StackOverflow™

                        
// never, never, NEVER use this!
function stripHtmlWithXss(html) {
  var tmp = document.createElement("DIV");
  tmp.innerHTML = html;
  return tmp.textContent || tmp.innerText;
}
                        
                    

                        
// never, never, NEVER use this! (part 2)
function jQueryStripHtmlWithXss(html) {
  return $('<div/>').html(html).text();
}

// … or jQuery's own parsing function
$.parseHTML();
                        
                    

                        
// Small change, but a safer solution
function stripHtmlSafe(html) {
  var tmp = document.implementation.createHTMLDocument();
  tmp.body.innerHTML = html;
  return tmp.body.textContent || tmp.body.innerText;
}
                        
                    

  • Patch für jQuery 1.12 und 2.2: $.parseHTML() künftig mit document.implementation.createHTMLDocument()

    Ergebnis: XSS-Code wird nicht mehr direkt getriggert …

  • … sondern erst beim ungefilterten Wiedereinsetzen in den DOM
  • Andere DOM-basierte Angriffe (z.B. DOM Clobbering) sind auch weiterhin möglich
  • Aber wir können zumindest darauf reagieren: DOM Purify

Richtiges Filtern ist schwierig

XSSed - Top sites by pagerank


  • ASCII-Steuerzeichen, Unicode-Symbole, escapete Sequenzen, etc.
  • Frameworks wie DOM Purify (JS), HTML Purifier (PHP) oder
    AntiSamy (Java, .NET) helfen.
  • Daten nie »einfach so« wieder ausgeben, sondern immer escapen
  • Beim Escaping immer auf den Kontext achten: HTML, CSS, JSON, etc.

Manche Browser helfen bei Reflected XSS

Man sollte sich aber keinesfalls ausschließlich darauf verlassen

Zusammenfassung: XSS

  • allen (allen, also wirklich ALLEN) Eingaben grundsätzlich misstrauen
  • Alle Eingaben sorgfältig validieren (Länge, Typ, Format)
  • Besondere Vorsicht bei HTML (z.B. Kommentare, WYSIWYG-Editor)
  • ggf. einzelne ausgesuchte Tags explizit erlauben (Whitelisting)
  • Markdown ist eine gute Alternative, auch für Kunden
  • Ebenfalls Zeichen- und Zeichenkodierung prüfen:
    (encodierte/escapete) Steuerzeichen, Unicode, etc.
  • »Escape your input, encode your output.«

(Un)geladene Gäste

Ausführen von ungewünschten Scripten verhindern

  • Filtern ist schwierig, es könnte uns etwas entgangen sein
  • Das Problem muss nicht auf unserem Server selbst auftreten
  • Die meisten Websites laden viele externe Ressourcen:
    Webfonts, Scripte von CDN-Servern, Werbung, Analytics-Zählpixel, etc.
  • All diese Quellen bergen auch ein potentielles Risiko
heise.de (6.01.2014): Yahoo.com griff europäische Besucher an

Abhilfe: Content-Security-Policy
(HTTP-Header)

Einschränkung der zu ladenden Ressourcen

Beispiel für CSP

index.html


<!DOCTYPE html>
<html>
<head>
    <script src="http://code.jquery.com/jquery.js"></script>
    <script src="http://evil.com/evil.js"></script>
</head>
<body>
    …
</body>
</html>
                    

Beispiel für CSP

.htaccess

                        
<IfModule mod_headers.c>
    Header always set Content-Security-Policy: ↩
      "script-src 'self' http://code.jquery.com"
</IfModule>
                        
                    

Beispiel für CSP

Laden des Codes von evil.com wird unterbunden:

CSP-Meldung in den Chrome Developer Tools

CSP-Medientypen

  • script-src: Laden von JavaScript
  • style-src: Gegenstück zu script-src für Stylesheets.
  • connect-src: Limitiert Verbindungen via Ajax, WebSockets, etc.
  • font-src: Web-Fonts (etwa TypeKit, Google Webfonts)
  • frame-src: Quellen, die per (i)frame in der Seite eingebettet werden dürfen (z.B. YouTube, Vimeo)
  • img-src: externe Quellen für Bilder …
  • media-src: … Audio/Video …
  • object-src: … sowie Flash und andere Plug-Ins.

Ab CSP Version 1.1:
frame-ancestors: Welche Domains dürfen die Seite per iframe einbetten?

Regeln

  • 'none': Einbindung verbieten
  • 'self': Aktueller Ursprung der Seite (ohne Subdomains)
  • 'unsafe-inline': Inline JavaScript und CSS
  • 'unsafe-eval': JavaScript-Parsing mit eval(), etc.

Oder Angaben nach Schema (data:, https:), Hostname (example.com),
URI (https://example.com:443) oder Wildcard (*://*.example.com:*)


Vorsicht: 'unsafe-inline' / 'unsafe-eval' führen alle
Inline-Scripte aus, auch mögliche XSS-Vektoren.

Beispiel für CSP

Das volle Programm: jQuery-CDN, Google Webfonts, Tumblr-Bilder, Youtube-Videos


<IfModule mod_headers.c>
    Header always set Content-Security-Policy: ↩
      "script-src 'self' code.jquery.com; ↩
      style-src 'self' http://fonts.googleapis.com; ↩
      font-src http://themes.googleusercontent.com; ↩
      img-src 'self' data: https://*.media.tumblr.com; ↩
      frame-src www.youtube.com; ↩
      object-src 'none'"
</IfModule>
                    

Browser-Support Content-Security-Policy

  • Chrome 25
  • Firefox 4+ (Versionen kleiner 23 als »X-Content-Security-Policy«)
  • Safari 6.1+
  • Opera 15+
  • Internet Explorer 10 (eingeschränkt)

Fazit

  • „Security by Default“: Schon beim Entwickeln daran denken
  • Clickjacking: Schutz aktivieren
  • XSS: allen Eingaben immer misstrauen: Sorgfältig validieren und filtern
  • CSP: Ungewollte Script-Ausführung verhindern
  • Vorsicht bei Proxies, die HTTP-Header ändern/löschen
  • Bei sensiblen Daten (z.B. Bankdaten/Kreditkarten),
    regelmäßig Security-Audit durchführen

… und zu guter Letzt

Es gibt keine 100%ige Sicherheit. Bleibt auf der Hut!

That's all folks!

Fragen?

Frederic Hemberger (@fhemberger)

 
Links und weitere Ressourcen

CSRF



X-Frame-Options

Cross-Site-Scripting (XSS)

Content Security Policy (CSP)

Sicherheit im Allgemeinen