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.
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.
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.
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.
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.
Ein Problem ist das Öffnen von neuen Fenster mit window.open()
. Diese Methode wird dazu missbraucht, um sogenannte Popup-Fenster (kurz: Popups) mit Werbung zu öffnen, die automatisch und unerwünscht aufspringen. Das unkontrollierte Öffnen von Fenstern belästigt die Nutzer nicht nur, sondern ist auch ein Sicherheitsproblem, denn es kann den Browser lahmlegen oder sogar zum Abstürzen bringen.
Aus diesem Grund haben mittlerweile alle Browser einen sogenannten Popup-Blocker eingebaut. Diese Blocker erlauben das Öffnen von Fenstern mittels JavaScript nur, wenn damit auf eine Benutzereingabe reagiert wird. Wenn sie also einfach window.open()
aufrufen, werden die meisten Popup-Blocker das Öffnen des Fensters unterbinden:
<script> window.open('dokument.html', 'fenstername'); </script>
Wenn Sie jedoch ein Fenster als Reaktion auf eine Benutzereingabe öffnen (siehe Event-Handling), erlauben es die Popup-Blocker üblicherweise. So können Sie beispielsweise ein a
-Element mit einem click
-Handler versehen. Ein einfaches Beispiel sähe so aus:
<a href="dokument.html" id="popup-link"> Dokument XYZ im eigenen Fenster öffnen </a>
Das JavaScript dazu (siehe Fortgeschrittene Ereignis-Verarbeitung):
function öffnePopupFenster(event) { window.open(event.target.href, 'popup'); } document.getElementById("popup-link") .addEventListener('click', öffnePopupFenster, false);
Popup-Blocker versuchen zwischen erwünschten und unerwünschten Popup-Fenstern zu unterscheiden. Ein Browser kann nicht zuverlässig unterscheiden, ob ein Fenster vom Anwender erwünscht ist oder nicht. Das angesprochene Kriterium der Benutzereingabe (z.B. ein Mausklick auf ein Element) ist nur bedingt tauglich: Manche Webseiten gaukeln dem Browser vor, sie würden ein »erwünschtes« Popup-Fenster als Reaktion auf eine Benutzereingabe öffnen, indem sie beim Klick irgendwo ins Dokument ein Werbe-Popup öffnen.
Es gibt keine allgemeingültigen Regeln, nach denen die verschiedenen Popup-Blocker arbeiten. Um Popup-Blocker möglichst zu umgehen, sollten Sie Fenster nur in Event-Handlern für das click
-Ereignis bei a
- oder button
-Elementen öffnen. Das obige Beispiel illustriert dies.
… 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…
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.
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.
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.
…
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. …