© DrHitch/Shutterstock.com
JavaScript Security

1 JavaScript in Angreiferhand


JavaScript-Code kann so wie jedes andere Computerprogramm auch Schwachstellen enthalten, und so wie in jeder anderen Programmiersprache können auch in JavaScript Schadprogramme geschrieben werden. Beide Möglichkeiten werden natürlich von Angreifern ausgenutzt – warum sollten sie auch darauf verzichten?

Erst einmal gilt wie fast überall: Alles, was Sie als Entwickler zum Vorteil der Benutzer verwenden können, können Angreifer auf die eine oder andere Weise zu ihrem Nachteil nutzen. Die möglichen Angriffe sind so umfangreich, dass sie den Platz für dieses Kapitel locker sprengen. Ich habe mich daher auf einen einzelnen Aspekt beschränkt: Schadcode im Webbrowser.

Los geht es mit einem altbekannten Problem, quasi der Wurzel allen Übels und die erste Möglichkeit, Schadcode in den Webbrowser einzuschleusen: Cross-site Scripting, kurz XSS. Dessen serverbasierte Varianten kennen Sie sicherlich:

  • Beim reflektierten XSS wird der Schadcode an die Webanwendung gesendet und von dieser in der erzeugten Webseite an den Client zurückgeschickt. Für den Angriff ist der Aufruf eines präparierten URL oder das Absenden eines präparierten Formulars nötig, die den XSS-Schadcode enthalten.
  • Beim auch JavaScript-Injection genannten persistenten XSS wird der Schadcode auf dem Webserver gespeichert, z. B. in einem Gästebucheintrag oder irgendeiner anderen Form von User-generated Content, und danach bei jedem Aufruf der betroffenen Seite ausgeliefert. Für den Angriff ist also nicht der Aufruf eines präparierten URL oder das Absenden eines präparierten Formulars nötig, sondern er erfolgt automatisch bei jedem Aufruf der Seite mit dem eingeschleusten Schadcode. Wie der Benutzer diese Seite erreicht, ist egal.

Meist werden im Rahmen von XSS-Angriffen Session-Cookies ausgespäht, falsche Informationen eingeschleust oder es wird Schadsoftware durch Drive-by-Infektionen verbreitet.

Wie Sie diese herkömmlichen XSS-Angriffe verhindern, wissen Sie sicher. Die Benutzereingaben müssen auf dem Server geprüft werden. Eingeschleuster HTML- oder JavaScript-Code muss von der Webanwendung entweder ausgefiltert oder z. B. durch Umkodieren der Zeichen < und > in die entsprechenden HTML-Entities &lt; und &gt; neutralisiert werden. Eigentlich ist das so selbstverständlich, dass es längst keine XSS-Schwachstellen mehr geben dürfte. Trotzdem tauchen sie immer noch auf, manchmal sogar in Form des absoluten Klassikers „XSS über den Suchbegriff der Suchfunktion“. Das ist natürlich äußerst schlecht, denn inzwischen sind viel weitreichendere Angriffe im Umlauf.

DOM-basiertes XSS

Schon seit 2005 gibt es eine weitere Form von XSS-Angriffen, die in Zeiten von AJAX (ein auch schon wieder aus der Mode gekommenes Buzzword) und erst recht HTML5 und den damit immer mächtigeren Webclients zunehmend an Bedeutung gewinnt: das DOM-basierte oder lokale XSS [1]. Der Schadcode wird dabei durch eine Schwachstelle im clientseitigen Skriptcode eingeschleust, also über eine Funktion innerhalb der betroffenen Seite, die die ihr übergebenen Daten ungeprüft ausgibt. Für den Angriff ist wie beim reflektierten XSS der Aufruf eines präparierten URL nötig, der den Schadcode enthält.

DOM-basiertes XSS unterscheidet sich in einem Punkt vom reflektierten oder persistenten XSS: Da der Schadcode zu keiner Zeit Bestandteil der vom Server gelieferten „rohen“ HTML-Seite ist, kann er von der Webanwendung, einem IDS/IPS oder einer Web Application Firewall darin auch nicht erkannt werden. Nur die im Request mitgelieferten Query-Daten verraten den Angriff. Und das kann unter Umständen auch noch umgangen werden kann, etwa indem der Schadcode als Fragmentbezeichner getarnt wird:

http://www.beispiel.example/index.html#parameter=<script>alert('XSS')</script>

Das #-Zeichen markiert den darauffolgenden Rest bekanntlich als Fragmentbezeichner. Dieser ist nicht Teil des URI, sondern enthält Referenzierungsinformationen, die vom Browser erst nach dem Empfang der Ressource lokal ausgewertet werden. Die meisten Browser senden den Fragmentbezeichner daher nicht an den Server, der dadurch nur

http://www.beispiel.example/index.html

zu sehen bekommt.

Wann ist DOM-basiertes XSS möglich?

Eine Webseite ist immer dann für DOM-basiertes XSS anfällig, wenn sie Daten aus vom Angreifer kontrollierbaren Objekten wie z. B. document.location, document.URL oder document.referrer ohne Prüfung auf eingeschleusten Code und ohne passende Umkodierung verwendet. Das klassische Beispiel ist eine Webseite, die den Besucher begrüßt (Listing 1.1, nach [1]).

Hallo 
<script>
var pos=document.URL.indexOf("name")+5;
document.write(document.URLsubstring(pos,document.URL.length));
</script>
, <br>
Willkommen auf unserer Website ...

Listing 1.1

Beim Aufruf dieser Seite wird der Benutzer mit seinem Namen begrüßt, etwa beim Aufruf von

http://www.beispiel.example/index.html?name=Adam

mit

Hallo Adam,
willkommen auf unserer Website

Der übliche XSS-Test mit

http://www.beispiel.example/index.html?name=<script>alert('XSS')</script>

führt dagegen zum Öffnen der Alertbox. Dieses Beispiel funktioniert nicht, wenn der Webbrowser den URL selbstständig URL-kodiert, denn dadurch werden die Zeichen < und > zu %3C und %3E, was die spätere Codeausführung verhindert. Diese Umkodierung verhindert aber keine Angriffe, die nicht auf < und > angewiesen sind.

DOM-basiertes XSS verhindern

Der einfachste Schutz vor DOM-basierten XSS-Schwachstellen besteht darin, auf dem Client weder Änderungen am DOM noch sensitive Aktionen mit vom Client gelieferten Daten zuzulassen. Wenn dafür Skripte auf dem Server zuständig sind, greifen die dort sowieso vorhandenen Schutzmaßnahmen.

Nun ist das in Zeiten von Web 2.0, HTML5 und erst recht angesichts der aufkommenden Offlineanwendungen illusorisch. Also müssen alle auf dem Client verarbeiteten Daten auch dort geprüft und bei Bedarf umkodiert werden. Und zwar am besten zuerst für HTML und danach für JavaScript. Statt

document.write("Benutzereingabe");

wird dann beispielsweise

document.write("<%=Encoder.encodeJS(Encoder.encodeHTML("Benutzereingabe"))%>");

verwendet, wobei encodeJS() und encodeHTML() z. B. die entsprechenden Funktionen des verwendeten JavaScript-Frameworks oder einer speziellen Bibliothek wie der JavaScript-Version des ESAPI (OWASP Enterprise Security API) [2] aufrufen.

Weitere Anleitungen zum Verhindern des DOM-basierten XSS finden Sie im „DOM based XSS Prevention Cheat Sheet“ des OWASP [3].

Schlimmer geht immer

DOM-basiertes XSS ist aber eigentlich auch schon wieder ein alter Hut, denn wie immer gilt: Schlimmer geht immer. Was hat uns HTML5 unter anderem beschert? Möglichkeiten, größere Mengen an Daten und damit auch JavaScript-Code dauerhaft auf dem Client zu speichern: Local Storage, Web-SQL-Datenbank und IndexedDB machen es möglich. Das schreit doch geradezu danach, für einen Angriff missbraucht zu werden. Nun, diese Schreie wurden erhört.

Rootkits für Webclients

Im Dezember 2011 hat Artur Janc auf dem 28C3 einen Vortrag mit dem Titel „Rootkits in your Web application“ gehalten [4]. Der Untertitel verrät bereits, wohin die Reise geht: „Achieving a permanent stealthy compromise of user accounts with XSS and JS injection attacks“.

Eigentlich ist „permanent“ und „JavaScript“ ja ein Widerspruch, sofern es um Webbrowser geht, denn normalerweise gilt: „Fenster zu, JavaScript-Code tot“. Wie soll das also funktionieren?

Fangen wir mal ganz am Anfang an: Wie kann man Benutzerkonten kompromittieren? Im klassischen Fall passiert das, indem der Angreifer sich Zugriff auf das Benutzerkonto auf dem Webserver oder ...

Neugierig geworden? Wir haben diese Angebote für dich:

Angebote für Teams

Für Firmen haben wir individuelle Teamlizenzen. Wir erstellen Ihnen gerne ein passendes Angebot.

Das Library-Modell:
IP-Zugang

Das Company-Modell:
Domain-Zugang