Angriffsvektor JavaScript

Transcription

Angriffsvektor JavaScript
Angriffsvektor JavaScript
Marcell Dietl
Hochschule RheinMain
Fachbereich Design Informatik Medien
Campus Unter den Eichen 5
65195 Wiesbaden
md@marcell-dietl.de
ZUSAMMENFASSUNG
1.
Das vorliegende Dokument ist im Rahmen des Fachseminars
Webbasierte Anwendungen des Studiengangs Angewandte
Informatik (B.Sc.) der Hochschule RheinMain im Wintersemester 2013/2014 entstanden.
Kaum eine Programmiersprache ist so eng mit dem Begriff
des Web 2.0 1 verbunden wie JavaScript. Nicht zuletzt an
dieser Verbundenheit dürfte es auch liegen, dass das USUnternehmen RedMonk in seinen Programming Language
Rankings [2] JavaScript als die populärste Programmiersprache der Welt ermittelt hat – gemessen an der Anzahl der
Projekte auf GitHub und der Tags auf Stack Overflow.
Ziel ist es, dem Leser einen kurzen Einblick in die diversen
Risiken zu ermöglichen, die der Einsatz von JavaScript – vor
allem im Web – mit sich bringt. Neben populären Angriffsvektoren, wie etwa Cross-Site Scripting, werden auch weniger bekannte beispielhaft beleuchtet. Mehreren Beispielen
liegt zudem Quellcode bei, mit dem diese einfach und praktisch nachvollzogen werden können.
Abschließend folgt ein grober Überblick zu möglichen Abwehrmaßnahmen. Jede Maßnahme wird kurz erläutert und
schließlich bewertet. Ausschlaggebend für die Bewertung ist,
welchen Aufwand es mit sich bringt, die Abwehrmaßnahme
bestmöglich ein- bzw. umzusetzen und welcher Nutzen sich
daraus ergibt.
EINLEITUNG
Betrachtet man sich die Sprach- bzw. Sicherheitskonzepte
von JavaScript, wird klar, warum gerade diese Programmiersprache prädestiniert für die Entwicklung von clientlastigen
Web 2.0 -Anwendungen zu sein scheint:
JavaScript ist eine eingebettete Skriptsprache, die stets in
einem Kontext ausgeführt wird, zum Beispiel clientseitig
im Browser. Dieser Kontext bestimmt, auf welche Objekte
Skriptcode zugreifen kann. Ein Zugriff auf das Dateisystem
ist im Browser-Kontext beispielsweise nicht vorgesehen.2
Sehr wohl vorgesehen ist allerdings der Zugriff auf Objekte
des Browsers, insbesondere gespeicherte Cookies3 . Die Same
Origin Policy (SOP) schränkt den Zugriff von Skriptcode
jedoch stark ein: auf jene Cookies der gleichen Herkunft4 .
Beide Konzepte, der Kontext eines Skripts und die SOP,
scheinen auf den ersten Blick ein ausreichender Schutz zu
sein, um JavaScript bedenkenlos einsetzen zu können. Dass
dem nicht so ist, belegen die vom Open Web Application
Security Project (OWASP) herausgegebenen Top 10 der kritischsten Schwachstellen in Webanwendungen [5].
Auf den Plätzen drei und acht finden sich jene Angriffsvektoren, die in den nächsten Abschnitten besprochen werden:
Cross-Site Scripting und Cross-Site Request Forgery. Beides
Angriffe, die vorwiegend durch JavaScript und dessen große
Verbreitung für Angreifer interessant wurden und meist auf
den Missbrauch von Cookies setzen.
1
2
3
4
Inhaltlich und technologisch sehr stark am Nutzer ausgerichtet. Siehe hierzu u. a.: http://de.wikipedia.org/
wiki/Web_2.0 (aufgerufen am 10.11.2013).
Statt Kontext spricht man auch von einer Sandbox, in
der JavaScript ausgeführt wird.
Kleine Textinformationen zur Identifikation von Benutzern. Siehe hierzu u. a.: http://de.wikipedia.org/wiki/
Cookie (aufgerufen am 10.11.2013).
Mit Herkunft ist im Falle der SOP das Tripel aus Protokoll, Domain und Port gemeint.
2. ANGRIFFSVEKTOREN
In diesem Kapitel werden verschiedene Angriffe, die mit
Hilfe von JavaScript realisiert werden können, praxisnah
beleuchtet. Manchen Szenarien ist beispielhafter Quellcode
beigelegt, damit diese leicht nachvollzogen werden können5 .
2.1 Cross-Site Scripting
Der vermutlich bekannteste Angriff, bei dessen Durchführung JavaScript eine wesentliche Rolle spielt, ist das so genannte Cross-Site Scripting (XSS) [4]. Es handelt sich hierbei um einen Spezialfall eines Content-Injection-Angriffs, bei
dem es einem Angreifer gelingt, eigenen Skriptcode innerhalb einer vertrauenswürdigen Webseite zu platzieren. Man
unterscheidet ferner zwischen min. zwei Arten von XSS:
Beim persistenten XSS wird der Skriptcode dauerhaft auf
dem Webserver gespeichert, zum Beispiel in Form eines BlogKommentars. Anschließend wird er bei jedem nachfolgenden
Seitenaufruf automatisch an alle Besucher ausgeliefert, was
zu einer hohen Verbreitung des Skriptcodes führt.
Das reflektierte unterscheidet sich vom persistenten XSS dadurch, dass der Skriptcode nicht auf dem Webserver abgelegt
wird und der Angriff häufig eine Nutzerinteraktion erfordert,
etwa den Aufruf einer manipulierten URL6 . In dieser ist der
Skriptcode meist Teil eines Parameters und wird erst beim
Aufruf und nur an einen einzigen Besucher ausgeliefert.
Für einen erfolgreichen Angriff fehlt nur noch der Schlussstein: Der Cookie muss heimlich an den Angreifer übertragen werden – statt dem Benutzer angezeigt zu werden. Dies
lässt sich mit einem recht simplen Standardtrick erreichen:
Der Angreifer platziert ein PHP-Skript log.php, das als Cookie Stealer fungiert, auf seinem eigenen Webserver, der zum
Beispiel unter http://www.example.org/ erreichbar ist. Dieses nimmt bei jedem Aufruf den GET-Parameter cookie entgegen. Anschließend wird einem Benutzer, ab jetzt auch
Opfer genannt, eine URL wie die nachfolgende zugespielt8 .
http://www.example.com/search.php?s=
<script>document.write(’<img width="0" height="0"
src="http://www.example.org/log.php?cookie=’
.concat(document.cookie).concat(’" ></img>’));
</script>
Sobald das Opfer die URL aufruft, sendet dessen Browser
eine GET-Anfrage an die im src-Attribut des img-Tags angegebene Adresse, um die Ressource zu laden. Mit Hilfe der
JavaScript-Methode concat()9 wird dieser Anfrage der Cookie des Opfers beigefügt. Um das offensichtliche Fehlen eines
Bildes zu verschleiern, wird dieses auf eine minimale Breite
und Höhe von 0 Pixeln reduziert.
Beiden Angriffen ist gemein, dass Sie nur funktionieren, wenn
eine Webanwendung Nutzereingaben, ob Blog-Kommentar
oder URL-Parameter, unzureichend gefiltert wieder ausgibt
– zum Beispiel eine Suchanfrage wie folgt beantwortet:
Der Angreifer kann sich nun mit Hilfe des Cookies gegenüber der Webseite http://www.example.com/ als das Opfer
ausgeben und Aktionen in dessen Namen tätigen. Die Gefährdung, die dadurch entsteht, ist jedoch stark vom Inhalt
und der Funktionsweise der Webseite abhängig.
Sie suchten nach: <?=$_GET[’s’]?>
Eine kleine News-Seite, die Cookies nur zu Werbezwecken
speichert, ist für einen Angreifer meist weniger von Interesse
als eine große E-Commerce-Seite mit hinterlegten Zahlungsinformationen. Damit der Angreifer auf Letzteres zugreifen
kann, müssen jedoch noch min. zwei weitere Bedingungen
erfüllt sein: Das Opfer muss zum Zeitpunkt des CookieDiebstahls auch auf der Seite angemeldet gewesen sein und
die Seite darf über keine weiteren Sicherheitsvorkehrungen
verfügen, zum Beispiel eine zusätzliche Passwort-Abfrage,
die beim Anzeigen sensibler Informationen verlangt wird.
In diesem sehr einfachen Beispiel wird ein GET-Parameter
völlig ungefiltert wiedergegeben. Vorausgesetzt, diese Seite ist über http://www.example.com/search.php erreichbar
und hat zuvor mit der Methode setcookie()7 ein Cookie im
Browser abgelegt, so lässt sie sich für reflektiertes XSS missbrauchen. Eine typische Test-URL sieht wie folgt aus:
http://www.example.com/search.php?s=
<script>alert(document.cookie);</script>
Ruft ein Benutzer diese URL auf, erscheint ein Pop-upFenster, in dem dieser den Inhalt seines eigenen Cookies
angezeigt bekommt. Das funktioniert, da die Webseite beliebigen Skriptcode ungefiltert ausliefert und JavaScript Zugriff auf Cookies der gleichen Herkunft hat, in diesem Fall
alle Cookies von http://www.example.com/.
2.2
8
5
6
7
Jeglicher Quellcode ist so weit abstrahiert worden, dass
er das Prinzip des Angriffs zwar deutlich macht, an und
für sich jedoch harmlos ist.
Uniform Resource Locator. Siehe hierzu u. a.: http://
tools.ietf.org/html/rfc1738 (aufgerufen am 10.11.2013).
Siehe hierzu u. a.: http://php.net/manual/de/function.
setcookie.php (aufgerufen am 10.11.2013).
Cross-Site Request Forgery
Auf Platz acht der OWASP Top 10 der kritischsten Schwachstellen in Webanwendungen [5] ist ein Angriff, der als CrossSite Request Forgery (CSRF, manchmal auch XSRF) [3]
bezeichnet wird. Ziel dieses Angriffs ist es, einen Benutzer
eine Aktion ohne dessen Wissen ausführen zu lassen – ihn
zum Beispiel zu einer Änderung des DNS10 -Server-Eintrags
in seinem Router zu veranlassen. Denn dann kann ein Angreifer den gesamten Internetverkehr nach Belieben lenken
9
10
Um keinen Verdacht zu erwecken, können längliche
URLs mit Hilfe von Kurz-URL-Diensten verschleiert werden. Siehe hierzu u. a.: http://de.wikipedia.org/
wiki/Kurz-URL-Dienst (aufgerufen am 11.11.2013).
Siehe hierzu u. a.: http://de.selfhtml.org/javascript/
objekte/string.htm (aufgerufen am 11.11.2013).
Domain Name System. Siehe hierzu u. a.: http://de.
wikipedia.org/wiki/Domain_Name_System (aufgerufen am 12.11.2013).
und die Zugangscodes besonders lohnenswerter Seiten mittels Phishing11 abzugreifen versuchen. Es lassen sich hierbei
min. zwei Arten von CSRF-Angriffen unterscheiden:
Jene, die eine GET-Anfrage absetzen und auch ganz ohne
JavaScript funktionieren und jene, bei denen das Versenden
einer POST-Anfrage benötigt wird, um die Manipulation
durchzuführen. Letzteres lässt sich mit Hilfe von JavaScript
besonders leicht automatisieren und verheimlichen.
Angenommen unter dem Hostnamen router ist das Webinterface eines ungenügend geschützten Routers zu erreichen.
Ungenügend meint in diesem Fall, dass das Webinterface
keine Passworteingabe verlangt und die Datei edit.php für
CSRF anfällig ist. Dieser Datei kann sowohl via GET als
auch POST der Parameter dns übergeben werden, der den
DNS-Server-Eintrag des Routers überschreibt.
Der Standardtrick besteht nun darin, dem Opfer eine HTMLE-Mail zu schicken, in der ein Bild mit einer Breite und Höhe von 0 Pixeln versteckt ist – ganz ähnlich dem Trick zum
Diebstahl von Cookies in Abschnitt 2.1:
Aber die wichtigste Bedingung von allen ist die, welche zu
Anfang schlicht unterstellt wurde: Das Wissen um den Hostnamen bzw. die IP-Adresse und das Vorhandensein eines
ebensolchen Webinterfaces auf Seiten des Opfers.
Bei genauerer Betrachtung ist Letzteres jedoch gar keine
allzu große Hürde. Viele Router sind über bekannte Hostnamen bzw. IP-Adressen zu erreichen. Findet ein Angreifer in einem der verbreiteten Modelle eine Lücke, wird der
Massenversand von E-Mails zwar zu vielen fehlgeschlagenen
Angriffen führen, aber immer noch zu einer beträchtlichen
Menge manipulierter Router.
Zudem sind CSRF-Angriffe nicht auf Router beschränkt,
sondern bereits mehrfach in bekannten Webseiten und sozialen Netzwerken vorgekommen. Und selbst zu streng eingestellte E-Mail-Clients sind keine wirkliche Hürde, wenn das
Opfer mit ein wenig Social Engineering14 zum Aufruf einer
Webseite bewegt werden kann, in welcher dann der eigentliche Angriffscode zur Ausführung kommt.
2.3
Browser History Stealing
<img width="0" height="0"
src="http://router/edit.php?dns=1.3.3.7">
Anfang 2010 wurden im Mozilla Security Blog unter dem
Titel Plugging the CSS History Leak [6] eine Reihe von Änderungen im hauseigenen Browser Firefox bekanntgegeben,
mit denen gleich drei Angriffen begegnet werden sollte. Alle
drei stellten eine Gefahr für die Privatsphäre der Nutzer dar,
da sie die Liste besuchter Webseiten auszulesen versuchten.
Lädt der E-Mail-Client des Opfers externe Bilder automatisch nach oder wurde dies explizit erlaubt, wird das Laden
des vornehmlichen Bildes zu einer GET-Anfrage führen, die
den DNS-Server-Eintrag des Routers überschreibt. Voraussetzung ist, dass das Opfer die E-Mail auf einem Rechner
betrachtet, der sich im gleichen Netz wie der Router befindet, sodass der Hostname router auch erreichbar ist.
Ein direkter Zugriff auf die History15 ist zwar nicht möglich gewesen, aber durch geschicktes Kombinieren mehrerer
Techniken konnte eine Liste vordefinierter URLs abgefragt
und je nach Reaktion des Browsers erkannt werden, ob der
Nutzer eine URL bereits besucht hatte oder nicht.
Will der Angreifer eine POST- statt einer GET-Anfrage
absetzen, so kann er beispielsweise auf die freie JavaScriptBibliothek jQuery12 zurückgreifen und sich der dortigen Methode post()13 bedienen:
<script>
$.post("http://router/edit.php",
{ dns: "1.3.3.7" } );
</script>
Beiden Varianten des beispielhaft durchgeführten Angriffs
ist gemein, dass sie nur dann ideal funktionieren, wenn eine
Reihe von Faktoren zusammenkommen. Neben der Grundvoraussetzung eines anfälligen und möglichst ungeschützten
Webinterfaces, bedarf es eines Opfers mit einem E-MailClient, der Ressourcen automatisch nachlädt und Skriptcode
ungefragt ausführt. Außerdem muss das Opfer die E-Mails
im richtigen Netz betrachten.
11
12
13
Kunstwort, mit dem das Abfischen von Passwörtern gemeint ist. Siehe hierzu u. a.: http://de.wikipedia.org/
wiki/Phishing (aufgerufen am 12.11.2013).
Siehe hierzu u. a.: http://jquery.com/ (aufgerufen am
12.11.2013).
Siehe hierzu u. a.: http://api.jquery.com/jQuery.post/
(aufgerufen am 12.11.2013).
Die ersten beiden Angriffe, denen in [6] Rechnung getragen wird, Layout Based Attacks und Timing Attacks, sollen
hier nicht weiter vertieft werden, da sie weniger JavaScript
als Angriffsvektor nutzten als vielmehr CSS16 bzw. zeitliche
Unterschiede beim Auswerten besuchter und nicht besuchter Seiten. Der letzte im Blogeintrag beschriebene Angriff,
Computed Style Attacks, wäre ohne JavaScript jedoch nicht
möglich gewesen, da er im Kern auf die JavaScript-Methode
window.getComputedStyle()17 angewiesen ist.
Mit dieser Methode lassen sich die CSS-Eigenschaften eines
jeden Seitenelements ermitteln, nachdem die in den CSSDateien hinterlegten Vorschriften angewendet wurden. Im
Falle der Computed Style Attacks waren diese Vorschriften
minimal: Mit Hilfe der Link-Pseudoklassen :link und :visited
14
15
16
17
Beeinflussung bzw. Manipulation von Menschen. Siehe hierzu u. a.: http://de.wikipedia.org/wiki/Social_
Engineering_(Sicherheit) (aufgerufen am 12.11.2013).
Gleichsam der Name eines JavaScript-Objekts, das
eingeschränkten Zugriff auf die Liste besuchter Webseiten ermöglicht. Siehe hierzu u. a.: https://developer.
mozilla.org/en-US/docs/Web/API/window.history
(aufgerufen am 12.11.2013).
Cascading Style Sheets. Siehe hierzu u. a.: http://de.
wikipedia.org/wiki/Cascading_Style_Sheets (aufgerufen am 12.11.2013).
Siehe hierzu u. a.: https://developer.mozilla.org/enUS/docs/Web/API/Window.getComputedStyle (aufgerufen am 12.11.2013).
wurden noch nicht besuchten und bereits besuchten Webseiten unterschiedliche Farben zugewiesen. Der Angriff bestand
dann in einer Schleife, die eine Liste vordefinierter URLs abgearbeitet hat und ihren Farbwert etwa wie folgt ermittelte:
window.getComputedStyle(link, null).
getPropertyValue("color")
Entsprach die Farbe der in link hinterlegten URL der von
:visited, konnte ein Angreifer ziemlich sicher sein, dass der
Nutzer diese Webseite besucht hatte. Eine Information, die
vor allem zu Werbezwecken missbraucht werden kann, da
sich aus der Liste besuchter Webseiten ein Persönlichkeitsprofil ableiten lässt.
Um dem Problem Herr zu werden, ist es Browsern seit Version 2.1 der CSS-Spezifikation erlaubt, alle Links wie nicht
besuchte Links zu behandeln oder andere Maßnahmen zu ergreifen, um die Privatsphäre der Nutzer zu schützen 18 .
Bezogen auf die im Beispiel verwendete JavaScript-Methode
window.getComputedStyle() bedeutet das konkret, dass Firefox diese bzgl. der Farbe der Links täuscht. Die Methode
liefert stets die Farbe von :link zurück. Somit erscheinen alle
Links als wären sie noch nicht besucht worden.
2.4 Web Proxy Detection
Mitte 2013 veröffentlichte der VPN-Anbieter ZorroVPN auf
seiner Webseite unter dem Titel Web proxy detection and
real IP address disclosure [10] einen Artikel, der mehrere
Wege beschreibt, mit der die Anonymität der Nutzer von
Web Proxys19 untergraben werden kann. Voraussetzung ist
lediglich, dass JavaScript im Web Proxy und Browser des
Nutzers aktiviert ist – was den Normalfall darstellt.
Angenommen in der Variablen our_host ist der Hostname
des Angreifers – example.org – hinterlegt und ein Benutzer
ruft eine dort hinterlegte Seite über einen beliebigen Web
Proxy auf. Dann reicht schon eine einzige Zeile JavaScript
aus, damit der Angreifer in Erfahrung bringen kann, ob der
Benutzer einen Web Proxy verwendet oder nicht:
if (window.location.hostname != our_host) { ... }
Trifft die Bedingung zu, weiß der Angreifer, dass seine Seite nur indirekt, eingebettet in eine andere Seite, den Web
Proxy, aufgerufen wird. Der Trick besteht schlicht darin,
dass JavaScript ungefiltert clientseitig ausgeführt wird und
die Eigenschaft hostname20 den wahren Hostnamen verrät.
Ferner lässt sich nicht nur ermitteln, von wo die eigene Seite aufgerufen wird, sondern auch, welcher Web Proxy zum
Einsatz kommt. Dazu reicht es aus, mit Hilfe von JavaScript
18
19
20
In eigenen Worten wiedergegeben. Originalwortlaut zu
finden unter: http://www.w3.org/TR/CSS2/selector.
html#link-pseudo-classes (aufgerufen am 12.11.2013).
Gemeint sind jene Proxys, die wie eine reguläre Webseite ausschließlich im Browser arbeiten.
Siehe hierzu u. a.: http://de.selfhtml.org/javascript/
objekte/location.htm (aufgerufen am 13.11.2013).
das Vorhandensein spezieller Werte zu überprüfen, die sich
von Web Proxy zu Web Proxy unterscheiden. Die drei im
Artikel getesteten lassen sich beispielsweise wie folgt voneinander unterscheiden und eindeutig identifizieren – jede
Zeile trifft auf einen anderen Web Proxy zu:
if (window["REAL_PROXY_HOST"]) { ... }
if (window["_proxy_jslib_SCRIPT_URL"]) { ... }
if (typeof ginf != ’undefined’) { ... }
Zwar ist dieser Trick nicht so generisch, wie der zuvor vorgestellte, dennoch sollte er sich mit nur geringem Aufwand auf
die bekanntesten öffentlich verfügbaren Web Proxys anwenden lassen. Dass er funktioniert, ist verständlich, wenn man
sich bewusst macht, wie ein Web Proxy grob funktioniert:
Jede Seite wird zuerst vollständig geladen und hinsichtlich
externer Ressourcen bzw. vorhandener Links untersucht. Jeder gefundene Link wird so abgeändert, dass ein Aufruf von
diesem wieder über den Web Proxy erfolgt. Anschließend
wird die Seite, eingebettet in den Code des Web Proxys,
dem Nutzer angezeigt. Und mit Hilfe von JavaScript lässt
sich nun clientseitig der sie umgebende Code des Web Proxys
auf verräterische Werte hin untersuchen.
Doch nicht nur JavaScript selbst wird ungefiltert bzw. ungenügend gefiltert an den Nutzer weitergegeben: Eine geschickte Maskierung eines Links innerhalb von JavaScript
kann dazu führen, dass dieser vom Web Proxy erst gar nicht
erkannt und somit auch nicht abgeändert wird. Sobald der
JavaScript-Code clientseitig ausgeführt wird, lädt der Browser die Ressource nicht über den Web Proxy, sondern direkt,
wodurch die echte IP-Adresse des Nutzers erkennbar ist.
Auch dieser Trick ist nicht so generisch, wie der zuerst vorgestellte, dennoch ließ er sich auf alle in [10] untersuchten Web
Proxys mit nur geringen Unterschieden anwenden. Die Vermutung liegt somit nahe, dass andere Web Proxys ebenfalls
dergestalt getäuscht werden können.
2.5
Server-Side JavaScript
In allen bisher behandelten Abschnitten wird JavaScript clientseitig ausgeführt und die Angriffe, die dadurch möglich
sind, stellen größtenteils eine Gefahr für den Nutzer, zumeist in der Rolle des Besuchers einer Webseite, dar. Doch
mit dem Aufkommen von Frameworks wie Node.js21 wird
JavaScript in zunehmendem Maße auch auf Seiten der Server
eingesetzt. Die Gefahren, die dadurch entstehen, fasst Sven
Vetsch in seiner OWASP-Präsentation Node.js Security: Old
vulnerabilities in new dresses [7] eindrucksvoll zusammen.
Anknüpfend an das Beispiel in Abschnitt 2.1 wird erneut
von einer Webanwendung ausgegangen, welche die Suchanfragen der Nutzer ungenügend filtert. Genauer gesagt: den
Inhalt des URL-Parameter s ungefiltert reflektiert. Die Seite
lausche wie gewohnt auf Port 8022 einer fiktiven URL.
21
22
Siehe hierzu u. a.: http://nodejs.org/ (aufgerufen am
13.11.2013).
Standard-Port des Hypertext Transfer Protocols. Siehe
hierzu u. a.: http://de.wikipedia.org/wiki/Hypertext_
Transfer_Protocol (aufgerufen am 16.11.2013).
Zum Verständnis sei folgender Quellcode gegeben:
var http = require(’http’);
var url = require(’url’);
Der Server antwortet daraufhin mit: Sie suchten nach: undefined. Im Hintergrund jedoch, in der Kommandozeile, in der
Node.js gestartet wurde, erscheint der Inhalt des aktuellen
Arbeitsverzeichnisses26 . Mit ein wenig mehr Fantasie kann
dieser Angriff so weit ausgebaut werden, dass ein Angreifer
vollständige Kontrolle über den Rechner erlangt.
http.createServer(function (req, res) {
res.writeHead(200, {’Content-Type’: ’text/html’});
var s = eval(url.parse(req.url, true).query.s);
res.end(’Sie suchten nach: ’ + s.search);
}).listen(80);
Nach dem Laden der Module http und url startet der obige Quellcode einen Server, der auf ankommende Anfragen
wartet, um diese mit dem Status-Code 20023 und der Ausgabe einer Zeile Text zu beantwortet. An dessen Ende ist der
Inhalt des zuvor extrahierten URL-Parameters s angehängt.
2.6
Die Liste ist keinesfalls vollständig, besonders da JavaScript
in immer größerem Umfang in immer mehr Bereichen zum
Einsatz kommt, beispielsweise als Programmiersprache für
Anwendungen mobiler Endgeräte oder als Teil von SQL27 Statements zum Abfragen von Datenbank-Inhalten.
3.
Dieser erwartet jedoch keine simple Zeichenkette, sondern
ein in JSON24 angegebenes JavaScript-Objekt. Eine TestURL zum Verifizieren der augenscheinlichen Anfälligkeit für
XSS-Angriffe sieht beispielsweise wie folgt aus:
http://www.example.com/?s=
({’search’:’<script>alert();</script>’})
Deutlich problematischer ist die immer noch weit verbreitete
Angewohnheit, empfangenes JSON mit Hilfe der Methode
eval()25 zu verarbeiten, um auf die Key-Value-Paare mittels
Punktnotation zugreifen zu können. Zur Verdeutlichung der
Problematik werde folgende Test-URL aufgerufen:
http://www.example.com/?s=
({’search’:2*2})
Der Server antwortet daraufhin mit: Sie suchten nach: 4. Er
hat den Inhalt folglich nicht nur verarbeitet, sondern auch
interpretiert. Bei einer einfachen Rechenaufgabe mag diese
Angewohnheit nicht allzu gefährlich, vielleicht sogar nützlich, wirken. Doch eval() macht keinen Unterschied zwischen
dem Lösen einer Multiplikation und dem Ausführen eines
Kommandozeilen-Befehls, wie das folgende Beispiel zeigt:
http://www.example.com/?s=
require(’child_process’).exec
("dir",
function (error, stdout, stderr)
{ console.log(stdout); })
23
24
25
Entspricht OK. Siehe hierzu u. a.: http://tools.ietf.org/
html/rfc1945 und http://tools.ietf.org/html/rfc2616
(aufgerufen am 16.11.2013).
JavaScript Object Notation. Siehe hierzu u. a.: http:
//de.wikipedia.org/wiki/JavaScript_Object_Notation
(aufgerufen am 16.11.2013).
Siehe hierzu u. a.: http://de.selfhtml.org/javascript/
objekte/unabhaengig.htm (aufgerufen am 16.11.2013).
Weitere Angriffsvektoren
Alle bisher aufgezeigten Schwachstellen und die daraus resultierenden Angriffe stellen lediglich eine grobe Auswahl
typischer Risiken dar, die der Einsatz von JavaScript mit
sich bringt.
ABWEHRMAßNAHMEN
In diesem Kapitel werden verschiedene Maßnahmen beleuchtet und bewertet, mit denen den zuvor beschriebenen Risiken, die der Einsatz von JavaScript mit sich bringt, serversowie clientseitig begegnet werden kann. Die Maßnahmen
sind als typische Vertreter verschiedener Ansätze zu verstehen und keinesfalls vollständig.
3.1
JavaScript abschalten / filtern
Einer der wohl radikalsten Ansätze, um sich als Nutzer vor
den meisten der bekannten JavaScript-Risiken zu schützen,
ist das clientseitige Abschalten bzw. Filtern von JavaScript.
Für Firefox steht beispielsweise das Add-on NoScript28 zur
Verfügung, das bereits über 2 Million Mal heruntergeladen
wurde und sowohl das Abschalten als auch das Filtern von
JavaScript ermöglicht. Wenngleich das Abschalten viele Angriffe effektiv verhindert, werden auch zahlreiche reguläre
Web 2.0 -Anwendungen ohne JavaScript anders als gewohnt
oder gar nicht mehr funktionieren. Für diese kann zwar anschließend eine Ausnahmeregel definiert werden, sodass sie
JavaScript ausführen dürfen, aber dann sind auch wieder die
meisten der eigentlich zu verhindernden Angriffe möglich.
Und mit dem Willen der Betreiber, JavaScript-freie Alternativen ihrer Web 2.0 -Anwendungen zu bieten, ist auch nicht
zu rechnen. Denn schon 2010 ermittelte Yahoo! in einer Studie [9], dass nur etwa 1 % der eigenen Besucher JavaScript
tatsächlich abgeschaltet hatten.
Hinzu kommt, dass JavaScript nicht mehr nur im Web Anwendung findet und ein Filtern aller erdenklichen Einsatzbereiche eine recht aufwendige Schutzmaßnahme darstellt,
die für weniger technikaffine Nutzer keine Option ist.
Fazit: In Einzelfällen ist das Abschalten bzw. Filtern von
JavaScript zwar sinnvoll, eine Lösung ist es aber nicht.
26
27
28
dir ist das Windows-Äquivalent des Linux-Befehls ls.
Structured Query Language. Siehe hierzu u. a.:
http://de.wikipedia.org/wiki/SQL (aufgerufen am
16.11.2013).
Siehe hierzu u. a.: http://noscript.net/ (aufgerufen am
25.11.2013).
3.2 Bug-Bounty-Programme29
Einen recht speziellen Weg, um Schwachstellen zu begegnen,
geht die Zero Day Initiative (ZDI)30 : Sie dient als Bindeglied
zwischen IT-Unternehmen und jenen, die Schwachstellen in
deren Produkten finden und ermöglicht Letzteren, diese anonym und für Geld zu verkaufen.
Den Herstellern bietet dieses Modell den großen Vorteil, dass
das Wissen um Schwachstellen in ihren Produkten nicht in
falsche Hände gerät und sie rechtzeitig reagieren können.
Neben der ZDI gibt es bereits mehrere Unternehmen, die eigene Bug-Bounty-Programme betreiben und Entdecker von
Schwachstellen für das verantwortungsvolle Melden 31 ebenjener entlohnen. So zahlt etwa Google bis zu 7500 USD für
gemeldete XSS-Schwachstellen der eigenen Diensten [1].
Fazit: Lohnender Ansatz, der die Sicherheit deutlich erhöht,
da gefundene Schwachstellen den Herstellern gemeldet und
von diesen zeitnah behoben werden können.
3.3 Secure Coding
Ein ebenso nachhaltiger wie auch aufwendiger Ansatz, um
Schwachstellen zu begegnen, stellt das sichere Programmieren aller Anwendungen dar. Zwar lässt sich dessen Grundgedanke – Traue keiner Benutzereingabe! – einfach formulieren, die Umsetzung ist aber zumeist deutlich komplexer.
Damit der vorgeschlagene Mechanismus greift, muss dieser
jedoch sowohl auf der Client- als auch auf der Server-Seite
unterstützt werden. Grund ist die Einführung des neuen
HTTP-Headers Content-Security-Policy, der vom Server gesendet, aber auch vom Client verstanden werden muss.
Mit diesem Header können Webanwendungen angeben, von
wo Inhalte, z. B. Bilder oder JavaScript, die innerhalb der
Seite genutzt werden, geladen werden dürfen. Ferner wird
eine strikte Trennung von Code und Daten angestrebt und
vom Verwenden besonders problematischer Methoden wie
eval() abgeraten. Eine ideale Umsetzung würde z. B. die zuvor vorgestellten XSS-Angriffe unterbinden, da sie auf dem
Einfügen von Code innerhalb der Webseite beruhen.
Doch ähnlich dem in Abschnitt 3.3 vorgeschlagenen sicheren
Programmieren als Abwehrmaßnahme, ist auch die Einführung von CSP und die damit verbundene Überarbeitung bestehender Anwendungen eine zumeist zeitintensive Aufgabe,
die einer schnellen Verbreitung im Wegen stehen dürfte.
Fazit: Wenngleich viele der angestrebten Maßnahmen, etwa
die strikte Trennung von Code und Daten, unabhängig vom
Erfolg von CSP eine gute Entscheidung darstellen, bleibt
fraglich, ob sich dieser Mechanismus, der sowohl vom Server als auch vom Client, herstellerübergreifend umgesetzt
werden muss, letztlich durchsetzen wird.
Damit Programme konsequent sicher programmiert werden
können, muss das Bewusstsein für Sicherheit fester Bestandteil des gesamten Entwicklungs- und Lebenszyklus von Software sein – von Anfang an. Auf veraltete Systeme, Programme und Methoden muss verzichtet und diese durch sichere
Alternativen ersetzt werden – auch auf Kosten der Kompatibilität, z. B. zu älteren Browsern.
4.
Häufig steht dem Willen, sichere Software zu entwickeln und
auf veraltete Techniken zu verzichten jedoch der Wunsch
nach einer möglichst großen Nutzerschaft bzw. das Vorhandensein von Legacy-Systemen32 im Weg. Auch die Schwierigkeit, sich unter Konkurrenten auf einen gemeinsamen sicheren Standard zu einigen, führt immer wieder zum Rückgriff auf bewährte unsichere Standards.
Idealerweise wird gerade bei neu entstehenden Webanwendungen die Chance genutzt, schon während der Entwicklung
auf Sicherheit Wert zu legen und diese während des gesamten Lebenszyklus im Blick zu behalten.
Fazit: Langfristig ist guter, sicherer Code auf Client- und
Server-Seite allen anderen Abwehrmaßnahmen vorzuziehen.
3.4 Content Security Policy
Eine recht neue Möglichkeit, Content-Injection-Angriffen wie
XSS zu begegnen, stellt ein vor allem von Google und Mozilla vorangetriebener Mechanismus namens Content Security Policy (CSP) dar, dessen erste Version [8] bereits den
W3C33 -Status Candidate Recommendation erreicht hat.
29
30
31
32
33
Bug ist engl. für Fehler. Bounty ist engl. für Prämie.
Siehe hierzu u. a.: http://www.zerodayinitiative.com/
(aufgerufen am 16.11.2013).
Häufig als Responsible Disclosure bezeichnet. Siehe hierzu u. a.: http://en.wikipedia.org/wiki/Responsible_
disclosure (aufgerufen am 16.11.2013).
Altsysteme. Siehe hierzu u. a.: http://de.wikipedia.org/
wiki/Legacy-System (aufgerufen am 16.11.2013).
World Wide Web Consortium. Siehe hierzu u. a.: http:
//www.w3.org/ (aufgerufen am 16.11.2013).
FAZIT
Wenngleich der Einsatz von JavaScript viele Risiken mit
sich bringt, wird dessen Verwendung kurz- bis mittelfristig wahrscheinlich noch weiter zunehmen. Vor allem dank
Frameworks wie jQuery und Node.js ist JavaScript nicht nur
leichter zu bedienen, sondern auch für ganz neue Aufgabenbereiche interessant geworden.
Die Zunahme an Bug-Bounty-Programmen und die Einführung von CSP zeigen bereits ein gestiegenes Bewusstsein für
Sicherheit und einen positiven Umgang mit denjenigen, die
auf Schwachstellen hinweisen.
5. LITERATURVERZEICHNIS
[1] A. Mein; M. Zalewski. Increased rewards for Google’s
Web Vulnerability Rreward Program.
http://googleonlinesecurity.blogspot.de/2013/06/
increased-rewards-for-googles-web.html
(aufgerufen am 16.11.2013).
[2] S. O’Grady. The RedMonk Programming Language
Rankings: January 2013.
http://redmonk.com/sogrady/2013/02/28/languagerankings-1-13/
(aufgerufen am 10.11.2013).
[3] OWASP. Cross-Site Request Forgery (CSRF).
https://www.owasp.org/index.php/Cross-Site_
Request_Forgery_(CSRF)
(aufgerufen am 11.11.2013).
[4] OWASP. Cross-Site Scripting (XSS).
https://www.owasp.org/index.php/Cross-site_
Scripting_(XSS)
(aufgerufen am 10.11.2013).
[5] OWASP. Top 10 2013.
https://www.owasp.org/index.php/Top_10_2013Top_10
(aufgerufen am 10.11.2013).
[6] S. Stamm. Plugging the CSS History Leak.
http://blog.mozilla.org/security/2010/03/31/
plugging-the-css-history-leak/
(aufgerufen am 12.11.2013).
[7] S. Vetsch. Node.js Security: Old vulnerabilities in new
dresses.
https://www.owasp.org/images/3/31/Node.js_
Security_Old_vulnerabilities_in_new_bottles__Sven_Vetsch.pdf
(aufgerufen am 13.11.2013).
[8] W3C. Content Security Policy 1.0.
http://www.w3.org/TR/CSP/
(aufgerufen am 16.11.2013).
[9] N. C. Zakas. How many users have JavaScript
disabled?
http://developer.yahoo.com/blogs/ydn/many-usersjavascript-disabled-14121.html
(aufgerufen am 16.11.2013).
[10] ZorroVPN. Web proxy detection and real IP address
disclosure.
https://zorrovpn.com/articles/web-proxy-detection
(aufgerufen am 12.11.2013).