JavaScript/Tutorials/Sicherheitskonzepte

Aus SELFHTML-Wiki
Wechseln zu: Navigation, Suche

Trotz des schlechten Rufs, den JavaScript in der stürmischen Anfangszeit des Webs hatte, ist es aus modernen Webanwendungen nicht mehr wegzudenken. In diesem Artikel sollen die Sicherheitskonzepte von JavaScript und Schutzmechanismen der Browser vorgestellt werden.

Der Einflussbereich der breit akzeptierten Kerntechniken (ECMAScript, das Browser Object Model sowie das Document Objekt Model) 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 clientseitigen Programmierung, die weit über die besagte Kerntechniken hinausreicht.

Die Browserhersteller sind bemüht, die Fähigkeiten von JavaScript zu erweitern, u. a. indem sie Schnittstellen zu bestehenden Techniken einbauen. Zum Beispiel im Internet Explorer hat JavaScript Zugriff auf ActiveX-Objekte und den sogenannten Windows Script Host. Darüber sind – zumindest prinzipiell – sicherheitskritische Zugriffe auf den Client-Rechner möglich. Nun sind diese Schnittstellen nicht für jedes Script verfügbar, sondern durch Sicherungsmechanismen geschützt. Weil diese jedoch in der Vergangenheit zu freizügig waren oder nicht hinreichend funktionierten, entstanden unzählige Sicherheitslücken.

Sicherheitskonzepte von JavaScript

Sandbox-Prinzip

Ein JavaScript verfügt im Vergleich zu anderen Computerprogrammen nur über begrenzte Möglichkeiten. Es operiert im Rahmen eines Browserfenster 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 Sandbox- oder Sandkastenprinzip.

Insbesondere kann ein gewöhnliches JavaScript auf einer Webseite keine Dateien auf dem Client-Rechner auslesen, geschweige denn Änderungen daran vornehmen. Es kann auch keine Betriebssystem- oder Browsereinstellungen ändern oder Software auf dem Client-Rechner 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 (engl. für Grundregel des selben Ursprungs) besagt, dass ein JavaScript eines Dokuments nur auf diejenigen anderen, fremden Dokumente zugreifen darf, die dieselbe Herkunft haben. Mit derselben Herkunft ist kurz gesagt die Domain in der URI des Dokuments gemeint.

Ein JavaScript hat zunächst einmal Zugriff auf das Dokument, an das es gebunden ist und in dessen Kontext es ausgeführt wird. Bei der Verwendung von Frames, Inner Frames 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 URI http://www.example.org/dokument1.html geladen und in einem anderen Frame desselben Framesets die URI http://www.example.org/dokument2.html. Diese beiden Dokumente haben denselben Ursprungsdomain, nämlich www.example.org. Daher können Scripte beider Dokumente gegenseitig auf das jeweils andere Dokument zugreifen, um z. B. Formulardaten oder Cookies auszulesen, über das DOM Änderungen vorzunehmen oder Anwender-Ereignisse zu überwachen.

Wenn die URI 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 ein schwerwiegendes Sicherheitsrisiko bei all denjenigen 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 auslösen und somit Daten vom Webserver empfangen oder an ihn übertragen. Die Same-Origin-Policy sorgt dafür, dass mit XMLHttpRequest nur HTTP-Anfragen an dieselbe Domain gesendet 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 URI http://www.example.net/script.js einbinden. Dieses Einbinden von Scripten von fremden Webservern ist gängige Praxis vor allem zum Einbinden von Online-Werbung und Statistik-Scripten. Aus der Perspektive der Sicherheit ist eine äußerst zweischneidige Praxis: Einerseits ist es ein sehr nützliches Feature, denn es macht z. B. die Nutzung von Webdiensten möglich. Andererseits kann es zu schwerwiegenden Sicherheitslücken führen, fremden Code in die eigene Seite einzubinden. Hauptartikel: JavaScript/Tutorials/Cross Site Scripting

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 rigide und streng scheinen, ist aber eine wichtige Sicherheitsbarriere. Diese Sperre geht davon aus, dass unter einer Domain verschiedene Websites liegen können, 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:

Beispiel
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:

Beispiel
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.

Local Machine Zone Lockdown

Die Same-Origin-Policy lässt einen Punkt außer Acht: Ein Script darf im Kontext der Herkunftsdomain ohne Begrenzung schalten und walten sowie mittels XMLHttpRequest Daten empfangen und versenden. Das kann zu einem schwerwiegenden Problem werden, wenn das Script nicht im Web, sondern lokal ausgeführt wird. Deshalb hat Microsoft mit dem Local Machine Zone Lockdown einen Sicherheitsmechanismus eingeführt.

Schutzmechanismen der Browser

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 Freiheiten 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.

Popup-Blocker

Das Öffnen neuer Fenster mit window.open wurde oft dazu missbraucht, um sogenannte Popup-Fenster (kurz: Popups) mit Werbung zu öffnen, die automatisch und ohne ausdrücklichen Wunsch des Websurfers aufspringen. Das unkontrollierte Öffnen von Fenstern war nicht nur lästig, sondern 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:

Beispiel ansehen …
function fensterOeffnen() { 
  window.open('https://forum.selfhtml.org/');
}
Durch einen Klick auf den Button wird die Funktion fensterOeffnen() aufgerufen, die mit window.open() ein neues Fenster in einer neuen Registerkarte öffnet.

Wenn Sie ein Fenster jedoch im Zuge der JavaScript-Behandlung (Event-Handling) einer Benutzereingabe öffnen, erlauben es die Popup-Blocker üblicherweise.

Beispiel ansehen …
function fensterOeffnen (Adresse) { 
  var text ='<p>ein neues Fenster!<br>(Besser wäre aber auf solche Popup-Boxen zu verzichten!)</p>';
  var MeinFenster = window.open(Adresse, "Zweitfenster", "width=300,height=400,left=100,top=200"); 
  MeinFenster.document.write(text); 
  MeinFenster.focus(); 
}

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 zur Unterscheidung tauglich: Manche Webseiten gaukeln dem Browser vor, sie würden ein »erwünschtes« Popup-Fenster als Reaktion auf eine Benutzereingabe öffnen, indem sie z. B. beim Klick irgendwo ins Dokument zusätzlich ein Werbe-Popup öffnen.

Es gibt keine allgemeingültigen Regeln, nach denen die verschiedenen Popup-Blocker arbeiten. Zudem können sie verschieden scharf eingestellt werden. Es ist daher schwierig, zuverlässige Aussagen darüber zu treffen, welche Popup-Fenster geblockt und welche zugelassen werden.

Empfehlung:
Sie sollten darauf verzichten, Fenster als Reaktion auf die dokumentweite Ereignisse zu öffnen. Das betrifft die Ereignisse load oder unload, aber auch Mausereignisse wie click oder Tastaturereignisse wie keypress bei zentralen Objekten wie window und document sowie bei den HTML-Elementen html und body. Solche Fenster werden höchstwahrscheinlich geblockt.
Wenn Sie punktuell Popup-Fenster öffnen wollen, dann geben sie einem a- oder button-Element einen Event-Handler für das click-Ereignis. Das obige Beispiel illustriert dies.

Die Veränderung der Fenstereigenschaften

Das Öffnen von neuen Fenstern bringt noch weiteres Missbrauchspotenzial und schwerwiegende Sicherheitsprobleme mit sich. Ursprünglich war es möglich, dass ein Script volle Kontrolle über das Aussehen und das Verhalten des neuen Fensters hatte.

Die window.open-Methode hat für diese Fensteroptionen einen dritten Parameter:

Beispiel
 window.open("dokument.html", "popup1", "top=1000,left=1000,width=10,height=10")

 window.open("dokument.html", "popup2", "location=no,menubar=no,resizable=no,status=no,toolbar=no")

Sie können sich den Missbrauch vorstellen, der dadurch ermöglicht wurde: Indem eine winzige oder überdimensionierte Größe und eine Position außerhalb des Bildschirmes angegeben wurde, konnte der Anwender das Fenster nicht sehen geschweige denn es auf die gewohnte Art schließen. Oder das Fenster hüpfte (mittels window.resizeBy, window.resizeTo sowie window.innerHeight und window.innerWidth) immer weg, sobald es der Anwender schließen wollte.

Das Verstecken der Menü-, Symbol-, Adress- und Statusleisten wurde auf breiter Front missbraucht, um Websurfern vorzugaukeln, sie befänden sich auf der Login-Seite einer anderen, ihnen bekannten und vertraulichen Webseite. Auf diese Weise werden im großen Stil persönliche Daten gestohlen – im Fachjargon nennt man diesen Datenklau Phishing.

Eine besonders perfide Gänglung des Benutzers erlaubten alte Versionen des Internet Explorers: Mit der Angabe der Fensteroption fullscreen=yes konnte ein Popup-Fenster im Vollbildmodus geöffnet werden. Über einen solchen Kiosk- oder Präsentationsmodus verfügen auch andere Browser, allerdings war es JavaScripten in anderen Browsern nicht erlaubt, diesen selbstständig zu aktivieren. Im Vollbildmodus war auf dem Bildschirm nichts als die Webseite zu sehen, alles andere wurde überlagert.

Heute sind aus diesen Gründen die Einflussmöglichkeiten von JavaScript auf die Darstellung von Browserfenstern stark eingeschränkt. Das Konzept des Tabbed Browsing stellt mehrere Dokumente innerhalb eines Fensters dar und macht diese über Registerkarten zugänglich. Der Einsatz von Popup-Fenstern ist nach und nach zurückgegangen, da die obene beschriebenen problematischen Fensterveränderungen beim Tabbed Browsing ihren Sinn verloren haben.

Empfehlung:
Verzichten Sie möglichst darauf, die Browserleisten mittels des dritten Parameter von window.open auszuschalten.Die Browser ignorieren ohnehin viele dieser Angaben und bestimmen die Anzeige von Menü und Leisten selbst.

Kontextmenü und rechte Maustaste

Als Kontextmenü wird das Aufklappmenü bezeichnet, das üblicherweise dann erscheint, wenn der Anwender ein Element der Webseite mit der rechten Maustaste anklickt. Je nach Hardware, Betriebssystem und Browser gibt es noch weitere Möglichkeiten, das Kontextmenü aufzurufen.

Dieses Kontextmenü ist für den Anwender enorm praktisch bei der Bedienung einer Webseite. Im Kontextmenü eines Links kann er zum Beispiel wählen, dass das Linkziel in einem neuen Fenster geöffnet wird oder die Zieladresse in die Zwischenablage kopiert wird.

Dessen ungeachtet versuchen zahlreichen Webseiten, mittels JavaScript die Anzeige dieses Kontextmenüs im gesamten Dokument zu unterbinden. Diese Scripte reagieren dokumentweit auf die Ereignisse contextmenu und mousedown und unterdrücken die Standardaktion des Browsers. Die Autoren wollen damit verhindern, dass Texte oder Bilder kopiert werden können oder der HTML-Quellcode gelesen werden kann. Meist wollen sie sich damit gegen eine urheberrechtswidrige Weiterverwendung der eigenen Werke schützen.

Es kann nüchtern festgestellt werden, dass das Sperren des Kontextmenüs diesen Zweck nicht zuverlässig erfüllt. Stattdessen richtet es mehr Schaden als Nutzen an. Wer Texte und Bilder kopieren möchte bzw. den Quelltext lesen will, schafft es ohne viel technisches Know-How auch trotz dieser »Rechtsklick-Sperre«.

Neuere Browser haben erkannt, dass das Sperren des Kontextmenüs den Benutzer gängelt und in der gewohnten Bedienung von Webseiten einschränkt. Sie bieten daher in ihrer Konfiguration die Möglichkeit, diese Sperren zu ignorieren. »Rechtsklick-Sperren« werden damit schlichtweg wirkungslos.

Es mag in besonderen Fällen, insbesondere speziellen Webanwendungen, seinen Sinn haben, ein eigenes, angepasstes Kontextmenü bereitzustellen. Aus diesem Grund ermöglichen verschiedene Browser die Behandlung des contextmenu-Ereignisses. Aber auch in dem Fall ist das Unterdrücken des browsereigenen Kontextmenüs nur möglich, wenn eine entsprechende Browsereinstellung dies zulässt.

Lang laufende Scripte

Heutige Webseiten werden immer größer. Neben den eigentlichen Inhalten werden Werbung und Analyse-Tools mit eingebunden. Diese werden im allgemeinen über JavaScript nachgeladen und mit document.write ins Dokument geschrieben. Da JavaScript single-threaded ist, arbeitet es ein Script nach dem anderen ab und blockiert währenddessen Darstellung und Benutzereingaben.

Screenshot: Fehlermeldung nicht antwortendes Skript

Die Web Worker-API ermöglicht es, rechenintensive Skripte in einen sogenannten „Hintergrundthread“ auszulagern. Diese werden dann in ihrem eigenen Prozess, im Hintergrund und getrennt von der Website ausgeführt ohne dabei die Benutzeroberfläche oder andere Skripts daran zu hindern, Interaktionen von Nutzern zu verarbeiten.

Beachten Sie: Während google Chrome alle in Tabs geöffneten Dokumente in einer Sandbox in jeweils eigenen Prozessen laufen lässt, und so die anderen Dokumente auch bei parallel lang laufenden Skripten zugänglich sind, haben der IE und Firefox noch keine Multiprozessarchitektur!

siehe auch:

Quellen

  1. Mathias Schäfer: JavaScript: Sicherheit

Siehe auch

Weblinks