JavaScript: Sicherheit

Einleitung

JavaScript wird oftmals als gefährlich und unsicher angesehen, sodass manche Webautoren auf JavaScript verzichten und Webnutzer die Ausführung von JavaScripten beschränken. Tatsächlich ist JavaScript nicht harmlos. JavaScript ist eine vollwertige Programmiersprache und JavaScript-Programme laufen auf Webseiten. Damit stellt sich das größten Einfallstor für schädlichen Code im Web dar.

JavaScript wird seit seinem Bestehen auch zur Gängelung und Irreführung der Nutzer eingesetzt. Moderne Browser haben deshalb Gegenmaßnahmen ergriffen, die die Möglichkeiten von JavaScript in verschiedenen Punkten beschneiden. Diese Einschränkungen werden wir kennenlernen.

Der Einflussbereich des Kernes von JavaScript (ECMAScript) ist relativ scharf umrissen. Ein JavaScript, das nur diese Techniken verwendet, hat begrenzte Möglichkeiten und damit ein vergleichsweise geringes Gefahrenpotenzial. Vorausgesetzt ist, dass die Browser grundlegenden Sicherheitskonzepte beachten. Auch diese werde im Folgenden vorgestellt.

Wenn Sicherheitslücken in Browsern entdeckt werden, ist in den meisten Fällen JavaScript im Spiel. Ein Teil dieser Lücken ermöglicht ein Umgehen der grundlegenden Sicherheitsbeschränkungen, ein anderer betrifft JavaScript-Erweiterungen. Denn JavaScript ist mittlerweile ein Türöffner für vielfältige clientseitige Programmierung, die weit über die Kerntechniken hinausreicht.

Die Browserhersteller sind bemüht, die Fähigkeiten von JavaScript zu erweitern, indem sie Schnittstellen zu bestehenden Techniken einbauen. Darüber sind sicherheitskritische Zugriffe auf den Client-Rechner möglich. Nun sind diese Schnittstellen nicht für jedes Script verfügbar, sondern durch Sicherungsmechanismen geschützt. Wenn diese nicht korrekt funktionieren, entstehen Sicherheitslücken.

Sicherheitskonzepte von JavaScript

Sandkastenprinzip

Ein JavaScript verfügt im Vergleich zu anderen Programmen nur über begrenzte Möglichkeiten. Es operiert im Rahmen eines Browserfensters und eines Dokumentes. Innerhalb dieses strengen Rahmens, in den das Script eingesperrt ist, darf es recht frei schalten und walten, denn es kann nur begrenzten Schaden anrichten. Diese grundlegende Beschränkung nennt sich Sandkastenprinzip (englisch sandbox).

Insbesondere kann ein gewöhnliches JavaScript nicht ohne Zustimmung Dateien auf dem Rechner des Webnutzers auslesen, geschweige denn Änderungen daran vornehmen. Es kann auch keine Betriebssystem- oder Browsereinstellungen ändern oder Software installieren.

Es gibt nur einige wenige Ausnahmen, in denen ein JavaScript über Browserfenster und Dokument hinaus operieren kann. Zum Beispiel kann es einige bestimmte Browserfunktionen aufrufen und einfache Dialogfenster sowie weitere Browserfenster öffnen. Diese Ausnahmen, die meist mit gewissen Einschränkungen verbunden sind, werden wir noch kennenlernen.

Same-Origin-Policy

Die Same-Origin-Policy (zu deutsch etwa: Grundsatz des selben Ursprungs) besagt, dass ein JavaScript in einem Dokuments nur auf diejenigen anderen Dokumente zugreifen darf, die dieselbe Herkunft haben. Mit derselben Herkunft ist kurz gesagt die Domain in der URL des Dokuments gemeint.

Ein JavaScript hat zunächst einmal Zugriff auf das Dokument, in das es eingebunden ist und in dessen Kontext es ausgeführt wird. Bei der Verwendung von Frames, Inner Frames (iframes) und Popup-Fenstern kann ein Script auch auf andere Dokumente zugreifen. Die Same-Origin-Policy schränkt diese dokumentübergreifenden Zugriffe ein.

Nehmen wir an, in einem Frame wird die URL http://www.example.org/dokument1.html geladen und in einem anderen Frame desselben Framesets die URL http://www.example.org/dokument2.html. Diese beiden Dokumente haben denselben Ursprung, nämlich www.example.org. Daher können Scripte beider Dokumente gegenseitig auf das jeweils andere Dokument zugreifen, z.B. um Formulardaten oder Cookies auszulesen, über das DOM Änderungen vorzunehmen oder Ereignisse zu überwachen.

Wenn die URL des zweiten Dokuments hingegen http://www.example.net/dokument2.html lautet, dann sperrt die Same-Origin-Policy den dokumentübergreifenden Zugriff. Denn der Ursprung ist unterschiedlich, einmal www.example.org und einmal www.example.net.

Ziel der Same-Origin-Policy ist, dass eine Webseite die Daten einer anderen nicht so einfach abgreifen kann. Dies wäre natürlich kein Problem, wenn die andere Webseite sowieso öffentlich ist. Es wäre hingegen eine schwerwiegende Sicherheitslücke bei Webseiten, die einer Anmeldung bedürfen und vertrauliche Daten anzeigen - zum Beispiel Webmail-Dienste, Communities und sämtliche personalisierbaren Webanwendungen.

Die Same-Origin-Policy greift auch bei XMLHttpRequest, besser unter dem Namen Ajax bekannt. Mit XMLHttpRequest kann ein Script HTTP-Anfragen senden, Daten an Webserver übertragen und schließlich Daten empfangen. Die Same-Origin-Policy sorgt dafür, dass mittels XMLHttpRequest nur Daten von derselben Ursprungsdomain empfangen werden können.

An einem Punkt greift die Same-Origin-Policy nicht: Ein HTML-Dokument kann mittels script-Element JavaScripte von fremden Domains einbinden. Diese werden mit denselben Rechten ausgeführt wie JavaScripte von derselben Domain. Beispielsweise kann http://www.example.org/dokument1.html das externe Script mit der URL http://www.example.net/script.js einbinden.

Solches Einbinden von Scripten von fremden Webservern ist leider Gang und Gäbe: Online-Werbung, Statistik-Scripte und Social-Media-Widgets werden so eingebunden. Aus der Perspektive der Sicherheit ist eine äußerst fragwürdige Praxis. Einerseits ist es ein nützliches Feature, denn es bringt Webdiensten auf die eigene Webseite. Andererseits ist es ein Sicherheitsrisiko, fremden Code in die eigene Seite einzubinden – wir werden später beim Cross-Site-Scripting darauf zurückkommen.

Same-Origin-Policy und Subdomains

Die Same-Origin-Policy blockt nicht nur den Zugriff, der sogenannte Second-Level-Domains übergreift (z.B. example.org darf nicht auf example.net zugreifen). Die Sperre blockt auch den Zugriff zwischen Subdomains derselben Domains. Das heißt, ein Script in einem Dokument unter de.example.org hat keinen Zugriff auf ein Dokument unter en.example.org, obwohl die Domain dieselbe ist (example.org) und sich bloß die Subdomain unterscheidet (de gegenüber en).

Diese Regelung mag zunächst streng scheinen, ist aber eine wichtige Sicherheitsbarriere. Denn es ist möglich, dass unter einer Domain verschiede Websites liegen, die ihre Daten nicht miteinander teilen wollen. Selbst wenn beide Domains zu einer Site gehören, lassen sich die verschiedenen Domains auf diese Weise kapseln und absichern.

Es gibt jedoch die Möglichkeit, dass ein Dokument einwilligt, dass es für den Zugriff von derselben Domain offen ist. In einem Dokument unter de.example.org wird folgende JavaScript-Anweisung notiert:

document.domain = 'example.org';

Damit ist das Dokument für Scripte zugänglich, die auf einer Domain liegen, die auf example.org endet. Also nicht nur für de.example.org, sondern auch für en.example.org oder hildegard.de.example.org.

Dieses Schema gilt nicht nur für Second-Level-Domains, sondern für beliebige Subdomains. Ein Script unter hildegard.de.example.org kann folgende Anweisung notieren:

document.domain = 'de.example.org';

Damit erlaubt es den Zugriff z.B. von mechthild.de.example.org und allen anderen Domains, die auf de.example.org enden.

Browser-Einschränkungen und Schutz vor schädlichen JavaScripten

JavaScript hat zwar keine vollständige Kontrolle über den Client-Rechner und den Browser, besitzt aber einige Möglichkeiten des Missbrauchs, mit denen der Benutzers irregeführt, belästigt und gegängelt werden kann. Mittlerweile besitzen die Browser eingebaute Schutzmechanismen, die gewisse Fähigkeiten von JavaScripten beschränken. Sie sollten diese kennen, denn sie werden bei der JavaScript-Entwicklung früher oder später an diese Grenzen stoßen.

Browser-Einschränkungen konfigurieren

… an welchen Stellen man das JavaScript-Verhalten der Browser einstellen kann.

IE 8: Extras > Popup-Blocker > Popupblockereinstellungen; Internetoptionen > Erweitert; Internetoptionen > Sicherheit > [Zone] > Skripting / Verschiedenes

Firefox 3.0: Extras > Einstellungen > Inhalt > JavaScript aktivieren > Erweitert…

Opera: Tools > Preferences > Advanced > Content > JavaScript Options…

Seitenspezifische Einstellungen

Ein wichtiges Sicherheitsfeature von Browsern sind Website-spezifische JavaScript-Einstellungen. Je nachdem, welche Website angesurft wird, wird die Ausführung von JavaScripten uneingeschränkt zugelassen, nur eingeschränkt zugelassen oder Scripte gar nicht ausgeführt. Dies trägt dem Umstand Rechnung, dass JavaScript als Haupteinfallstor für die Ausnutzung von Browser-Sicherheitslücken dient, zur Gängelung des Anwenders missbraucht wird oder enfach unerwünschte Werbung einbindet.

Diese seitenspezifischen Einstellungen sind von Browser zu Browser unterschiedlich umgesetzt und betreffen nicht nur JavaScript, sondern auch andere sicherheits- und datenschutzkritische Techniken wie Cookies und Plugins.

Internet Explorer

Der Internet Explorer verfügt über verschiedene Sicherheitszonen, die standardmäßig an gewisse Einstellungen gekoppelt sind. Eine normales HTML-Dokument im World Wide Web liegt in der Internetzone, ein Dokument auf dem lokalen Rechner oder im lokalen Netzwerk in der Zone Lokales Intranet.

Daneben existieren zwei Zonen, zu denen der Anwender eigenständig Webadressen und Netzwerk-Pfade hinzufügen kann: Vertrauenswürdige Sites und Eingeschränkte Sites. Dies erlaubt dem Anwender beispielsweise, für die Internetzone eher restriktive Sicherheitseinstellungen zu wählen, die dann für bestimmte Seiten gelockert werden können.

Firefox

Mozilla Firefox verfügt intern über seitenspezifische Einstellungen, bietet standardmäßig aber keine Menü an, über das der Anwender die Einstellungen komfortabel regulieren könnte. Der Firefox-Zusatz NoScript erfreut sich jedoch einiger Verbreitung. Dieser erlaubt das seitenweise Erlauben oder Verbieten der Ausführung von JavaScripten und kann Scripten weitere Beschränkungen auferlegen.

Safari

Cross-Site Scripting (XSS)

Cross-Site Scripting, abgekürzt XSS, ist das Einschleusen von fremden, möglicherweise schädlichen JavaScripten in eine Website. Es handelt sich weniger um ein Sicherheitsproblem innerhalb von JavaScript, sondern um eine Sicherheitslücke in fehlerhaften Webanwendungen. Wenn Webanwendungen Daten aus nicht vertrauenswürdigen Quellen (z.B. aus Formulareingaben oder HTTP-Parametern) ungefiltert ins HTML einbauen, so können Angreifer schlimmstenfalls dauerhaft JavaScript-Code einschmuggeln.

Dieser Code besitzt alle Zugriffsrechte, die ein JavaScript auf der Website üblicherweise hat. Handelt es sich um eine per Login geschützte Anwendung, so kann das Script im Namen des Benutzers Aktionen vornehmen. Denn ein eingeschleustes Script kann HTTP-Anfragen versenden, private Daten auslesen, ändern und verschicken. Der Benutzer nimmt davon meist keine Notiz. Die Webanwendung kann nicht einfach unterscheiden, ob der Benutzer selbst Urheber der Aktionen ist oder ein schädliches JavaScript.

XSS-Lücken in großen Webanwendungen wie Facebook und Twitter haben spektakuläre JavaScript-Würmer möglich gemacht. Diese pflanzten sich innerhalb der Website z.B. über Benutzerprofile fort, konnten private Daten auslesen oder löschen und damit großen Schaden anrichten. Es gibt auch XSS-Würmer, die andere Domains mit derselben Webanwendung (z.B. der Blogsoftware WordPress) infizierten und sich so über Webserver hinweg verbreiteten.

Um XSS-Lücken zu vermeiden, ist eine sorgfältige Prüfung, Filterung und Entschärfung aller nicht vertrauenswürdiger Daten nötig, die in den HTML-, CSS- und JavaScript-Code server- oder clientseitig eingebaut werden. …