Frontend – Websecurity

Websecurity war lange ein unterschätztes und wenig behandeltes Risiko. Seit Angriffen auf große Portale kommt das Thema immer öfter zur Sprache bzw. es werden Sicherheitsmaßnahmen geschaffen.

In diesem Artikel möchte ich im speziellen auf Frontend-Websecurity eingehen, also sicherheitsrelevante Themen, die auch ohne Backend existieren können.

Neues Fenster (target=“_blank“)

Ein aktuell diskutiertes Problem kann ein normaler Link sein, der in neuem Fenster/Tab geöffnet wird (target=“_blank“), wenn dieser auf eine externe Seite führt, die nicht unter der eigenen Kontrolle ist. Wird ein neues Fenster mit einem solchen Link geöffnet, hat die geladene Seite teilweise Zugriff auf die aufrufende Seite. Das gilt ebenso für Fenster die per Javascript (window.open) geöffnet werden. Eine geöffnete Seite kann die URL des Urspungsfensters umbemerkt beeinflussen (window.opener.location = ‚http://…';) und somit beispielsweise auf eine Phishingseite umleiten. Dieser Angriff ist bekannt dafür, bei Facebook zu funktionieren. Er kann dazu verwendet werden beispielsweise Login-Daten zu Facebook-Accounts zu stehlen. Wichtig dabei ist, dass selbst eigentlich vertrauenswürdige verlinkte Seiten zu einem Problem werden können, wenn diese eine stored XSS (Cross-Site-Script) Lücke aufweisen. Über eine solche kann ein Angreifer beliebigen Code auf der betroffenen Seite platzieren, somit auch ein entsprechendes Skript zum Steuern des aufrufenden Fensters.

Eine (Teil-)Lösung des Problems bietet das rel-Attribut. Ist der Link mit rel=“noopener noreferrer“ ausgezeichnet, verbietet der Browser den Zugriff durch die geöffnete Seite.
Um das Problem bei per Javascript geöffneten Fenster zu unterbinden, muss auch hier der opener deaktiviert werden:

var win = window.open();
win.opener = null;

Leider funktioniert dieser Schutz nicht bei jedem Browser, wie etwa dem Safari-Browser.

Auf einer Github-Seite von Mathias Bynens sind zu dieser Sicherheitslücke und möglichen Lösungen Beispiele zu finden.

Client XSS

Cross-Site-Scripting ist ein altbekanntes Sicherheitsproblem. Meist trifft man darauf im Zusammenhang mit im Backend gespeicherten Daten. Werden hier zum Beispiel Nutzerkommentare nicht korrekt bereinigt, können diese bei der Ausgabe schädlichen Inhalt enthalten. Hier sollte im Frontend darauf geachtet werden, dass dynamisch geladene Daten – wenn möglich – vor der Ausgabe im Browser immer bereinigt (validiert/escaped) werden, auch wenn sie vom „eigenen“ Backend kommen.

Auch rein im Frontend können XSS-Lücken existieren: Werden Daten aus der URL unbereinigt im Inhalt ausgegeben, kann über eine URL, die entsprechend manipuliert verschickt wird, beim Nutzer ebenfalls Schadcode ausgeführt werden. Ein Beispiel hierfür kann eine Suchseite sein, bei der der Suchparameter in der URL angehängt und dann per Javascipt in der Seite ausgegeben wird. Eine weitere Angriffsfläche für XSS sind Skripte die von externen Servern eingebunden werden. Dazu zählen häufig JavaScript-Bibliotheken, die in CDNs gehostet werden, sowie Tracking- und Werbe-Einbindungen.

Bei der Nutzung solcher externen Ressourcen muss immer bewusst sein, dass ein Angreifer auch in die eigene Seite Schadcode einbinden kann, wenn diese externen Ressourcen Sicherheitslücken enthalten. Um die Möglichkeiten für Cross-Site-Scripting zu reduzieren, können zusätzlich Content-Security-Policy-Regeln (CSP) definiert werden. Über diese Regeln wird der Aufruf von bestimmten Inhalten gezielt eingeschränkt, und ein Angriff  im Zweifel abgewehrt – selbst wenn eine Sicherheitslücke existiert.
Es können dabei Quellen/Ziele folgender Ressoucen gesteuert werden:

  • Scripts => script-src
  • Style-Sheets => style-src
  • Webfonts => font-src
  • Bilder => img-src
  • Audio/Video => media-src
  • Flash und anderen Plugins => object-src
  • Verbindungsziele (z.b. Ajax oder Websockets) => connect-src
  • (i)Frames => frame-src

Zu jedem genannten Attribut können beliebig viele Quellen definiert werden. Solange kein entsprechender CSP-Eintrag besteht, erlaubt der Browser sämtliche URLs. Sobald ein Eintrag definiert ist, werden von der jeweiligen Kategorie nur noch Quellen angenommen, die explizit freigegeben wurden. So kann beispielsweise per ‚self‘ Eintrag ausschließlich die eigene Domain als Quelle für nachgeladene Inhalte erlaubt werden.

Content-Security-Policy: „script-src ‚self‘ http://example.com; style-src ‚self'“

In diesem Beispiel werden Scripts nur noch von der eigenen Domain und von example.com, sowie Stylesheets von der eigenen Domain geladen. Bilder, Frames etc. werden weiterhin von jeder Domain angenommen, da hier keine CSP definiert ist.

Zur Analyse der verwendeten Quellen ist es möglich, einen Reporter-CSP-Eintrag zu erstellen, dafür muss ein entsprechendes Skript zum Empfang der Daten (hier: log.php) erstellt werden:

Content-Security-Policy-Report-Only: „default-src ‚self'; report-uri /log.php“

Zum Testen von CSP-Regeln beitet sich die Browser-Erweiterung „CSP-Tester“ an.

Eine Übersicht zu CSP liefert das Mozilla-Developer-Network.

Iframe

Grundsätzlich sollte man bedenken, dass die Verwendung eines iFrames bedeutet, dass man dem Inhalt und der Sicherheit der eingebundenen Seiten vertraut.
Zusätzlich ist empfehlenswert, eingesetzte iFrames sicherer zu machen. Dies ist gut über das Sandbox-Attribut möglich: dieses schränkt die erlaubte Funktionalität im Frame ein. Es kann zum Beispiel unterbunden werden, dass im Frame JavaScript ausgeführt wird.

Zur sinnvollen Nutzung des Sandbox-Attributs muss dabei zunächst analysiert werden, welche Funktionen das jeweile iFrame benötigt, um diese dann explizit zu erlauben. Eine gute Erklärung mit Beispielen findet man dazu auf HTML5rocks.

Click-Jacking

Als Click-Jacking bezeichnet man einen Angriff, bei dem ein Nutzer unbewusst auf der eigenen Seite eine Aktion ausführt. Dazu bindet ein Angreifer auf einer Click-Jacking-Seite die Zielseite in einem iFrame ein, macht diese transparent und somit für den Nutzer unsichtbar. Dabei wird das iFrame so positioniert, dass ein Button o.ä. genau an der Stelle der Seite ist, die der Nutzer anklickt, da ihm eine andere Aktion suggeriert wird. Teilweise wird dazu auch ein Skrip eingesetzt, dass das iFrame ständig so verschiebt, dass sich der Button unter dem Mauszeiger befindet und es somit egal ist, an welcher Stelle der Nutzer klickt.

Um eine Seite vor Click-Jacking zu schützen, können sogenannte Frame-Busting-Technologien eingesetzt werden. Es handelt sich dabei um Skripte, die erkennen, wenn die Seite in einem Frame geladen wurde, und versuchen aus dieser auszubrechen. Dabei ist zu beachten, dass diese Techniken nicht immer funktionieren. Es bedarf also weiterer Sicherheitsmaßnahmen. Zum Beispiel kann ein Button eines Formulars erst dann aktiviert werden, wenn ein Skript erkennt, dass die Seite nicht in einem Frame geladen ist.

if (top == self) $button.prop(‚disabled‘, false);

Man sollte dabei genau überlegen, ob es nicht doch einen Fall gibt, in dem es gewünscht ist, die Seite in einem Frame einzubinden. Dazu zählt, als prominentes Beispiel, die Google Bildersuche. Sie stellt Seiten ebenfalls in einem Frame dar – völlig legitim.

Sehr sinnvoll sind „X-Frame-Options“. Mit diesen kann dem Browser mitgeteilt werden, ob beziehungsweise von wem die eigene Seite in einem Frame eingebunden werden darf.

  • X-Frame-Options: DENY
    • Einbinung in Frames nicht erlaubt
  • X-Frame-Options: SAMEORIGIN
    • Einbindung in Frame der selbe Domain und des selben Protokolls
  • X-Frame-Options: ALLOW-FROM origin
    • Einbindung von definierter URL

 


Ich hoffe, dieser Artikel kann auf Frontend Websecurity aufmerksam machen, und hilft dabei, Sicherheitslücken zu verstehen und zu beheben.

Klar sollte aber sein: Dieser Artikel erhebt keinen Anspruch darauf vollständig zu sein, bei der Entwicklung und Nutzung sollte man stets wachsam sein und auch mal „um die Ecke“ denken.

Hinterlasse eine Antwort

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind markiert *

*

*

Du kannst folgende HTML-Tags benutzen: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>