© DrHitch/Shutterstock.com
JavaScript Security

2 HTML5-Grafikffunktionen gefährden Sicherheit und Privatsphäre


Seit dem Jahre 2012 wurden zahlreiche neue Angriffe entwickelt, zum Beispiel Hacks, die die neuen Grafikfunktionen zum Ausspähen oder Tracken der Benutzer verwenden. Dieses Kapitel befasst sich mit den Grafikfunktionen in HTML5 und den von ihnen ausgehenden Gefahrenpotenzialen.

Die Same-Origin Policy, ein massives Bollwerk

Sie wissen es ja sicher: Die Same-Origin Policy (SOP) ist der beste (und einzige) Schutz der im Browser dargestellten Seite vor Zugriffen durch bösartigen JavaScript-Code von fremden Domains. Nur Code, der von Ihrer eigenen Domain geladen wurde, darf auf Ihre Seite zugreifen und dort Daten lesen und/oder Elemente manipulieren. Bösartigem JavaScript-Code von anderen Domains bleibt der Zugriff auf Ihre Seite verwehrt. Ein Angreifer, der Daten auf Ihrer Seite ausspähen will, ist also auf eine Cross-Site-Scripting-Schwachstelle in Ihrem Code angewiesen. Und die gibt es ja wohl hoffentlich nicht.

Soweit die Theorie. In der Praxis würde dem Angreifer auch jede andere Schwachstelle ausreichen, über die er auf Ihre Seite zugreifen kann. Das könnte zum Beispiel eine Schwachstelle im Browser sein, durch die sich trotz SOP Daten anderer Domains ausspähen lassen. Einige derartige Möglichkeiten hat Paul Stone 2013 auf der Sicherheitskonferenz Black Hat USA vorgestellt. Sein Vortrag hatte den Titel „Pixel Perfect Timing Attacks with HTML5“ [3], und dieser verrät schon, worum es im Folgenden geht:

Timing-Angriffe im Browser ...

Ganz allgemein wird bei Timing-Angriffen ausgewertet, wie lange eine Operation dauert und darüber auf die verarbeiteten Daten geschlossen. Eine für so einen Angriff verwendete Browserfunktion muss einige Anforderungen erfüllen:

  1. Die Funktion muss über JavaScript auslösbar sein.
  2. Sie muss während der Layout- oder Zeichenschritte des Browsers ausgeführt werden.
  3. Zweckmäßigerweise sollte die Funktion Daten verarbeiten, die zum einen nicht selbst über JavaScript gelesen werden können und zum anderen sensitiv genug sind, um als Angriffsziel interessant zu sein.
  4. Die Funktion muss je nach verarbeiteten Daten unterschiedliche Laufzeiten aufweisen, aus denen dann auf die Daten geschlossen werden kann.

Jede Funktion, die diese vier Anforderungen erfüllt, kann ein brauchbares Ziel für einen Timing-Angriff zum Ausspähen sensitiver Informationen sein.

... mit dem „requestAnimationFrame“-JavaScript-API

Beim ersten von Paul Stone vorgestellten Angriff wird für den Angriff das requestAnimationFrame-JavaScript-API verwendet. Das stellt die gleichnamige Methode bereit, mit der dem Browser signalisiert wird, dass eine skriptbasierte Animation aktualisiert werden muss [4]. requestAnimationFrame verwendet einen einzigen Parameter: Eine Callback-Funktion, die aufgerufen wird, bevor der nächste Frame auf den Bildschirm gezeichnet wird. Dabei wird der Callback-Funktion ein Timestamp-Parameter übergeben, über den sie erfährt, wann sie aufgerufen wurde.

„requestAnimationFrame“, ganz harmlos

Das soll den Entwicklern die Möglichkeit geben, zwischen der Darstellung von Animations-Frames notwendige Aktionen auszuführen. Das kann zum Beispiel die Ausführung einer JavaScript-Funktion sein, die Berechnung der Positionen neuer oder geänderter Elemente oder das Zeichnen von Elementen auf den Bildschirm. Je nach Komplexität der Aktion dauert diese mehr oder weniger lange. Der an die Callback-Funktion übergebene Timestamp-Parameter kann verwendet werden, um die Laufzeit der innerhalb der Callback-Funktion ausgeführten Aktionen zu berechnen.

Wird requestAnimationFrame wiederholt aufgerufen, versucht die Funktion bis zu sechzig Frames pro Sekunde zu erzeugen, also ungefähr alle 16 Millisekunden einen Frame. Der Aufruf der Callback-Funktion wird dabei passend eingeplant. Dauert die Ausführung eines Aufrufs der Callback-Funktion länger als 16 ms, wird die Erzeugung des nächsten Frames so lange verzögert, bis die Funktion beendet wurde. Diese Verzögerung und damit die Frame-Rate kann mit requestAnimationFrame gemessen werden. Mit dem Code in Listing 2.1 (nach Figure 3 aus dem Whitepaper zu [3]) kann die Frame-Rate einer Webseite ermittelt werden, indem die zwischen jedem erzeugten Frame verstrichene Zeit berechnet wird.

var lastTime = 0;

function loop(time) {
// die Callback-Funktion zur Berechnung der Laufzeit
// time = Timestamp des aktuellen Aufrufs
var delay = time – lastTime;
var fps = 1000/delay;
console.log(delay + ' ms' fps);
updateAnimation();
requestAnimationFrame(loop);
lastTime = time;
}

requestAnimationFrame(loop);

Listing 2.1: Berechnung der Frame-Rate einer Website

Mit „requestAnimationFrame“ lässt sich die History ausspähen

Es gibt schon eine größere Anzahl von Angriffen, um mithilfe von CSS-Features und JavaScript-Funktionen zu prüfen, ob ein bestimmter URL bereits vom Benutzer besucht wurde oder nicht. Paul Stone hat mehrere neue Verfahren entwickelt, die auf HTML5 basieren.

Das Link-Rendering und Redraw-Events

Im Folgenden wird nur der Angriff auf den Firefox-Browser beschrieben. Paul Stone hat auch Angriffe über den Internet Explorer und Chrome vorgestellt, die hier aus Platzgründen nicht betrachtet werden können.

Für alle auf einer Webseite enthaltenen Links muss der Browser prüfen, ob sie mit dem Style für besuchte oder nicht besuchte Links dargestellt werden müssen. Dazu verwaltet der Browser eine Datenbank mit den zuvor besuchten URLs, zum Beispiel in Form der History, und sieht für jeden Link auf der Seite nach, ob er in der Datenbank enthalten ist oder nicht.

Der Firefox verwendet dafür asynchrone Datenbankabfragen: Ist die Datenbankabfrage nicht beendet, bevor der Link gerendert wird, wird er zunächst mit dem Style für „nicht besucht“ dargestellt. Wenn die Antwort auf die Datenbankabfrage dann kommt und ergibt, dass der Link bereits besucht wurde, wird ein Redraw mit dem Style für besuchte Links ausgelöst. Kann eine Webseite diesen Redraw-Event erkennen, kann sie darüber zwischen besuchten und nicht besuchten Links unterscheiden.

Ein Redraw wird auch ausgelöst, wenn sich das Ziel eines Links ändert, zum Beispiel weil über JavaScript das href-Attribut geändert wird. Ändert sich dabei der „Besuchsstatus“, wird der Style entsprechend geändert. Listing 2.2 (nach Figure 5 aus dem Whitepaper zu [3]) zeigt die Änderung des href-Attributs.

<a href="http://www.google.de" id="link1">Der Link</a>

<script>
var el = document.getElementById('link1');
el.href = 'http://www.http://www.bing.com/?cc=de';
// Firefox passt den "Besuchsstatus" jetzt automatisch an.
</script>

Listing 2.2: Änderung des „href“-Attributs in Firefox und Chrome

Redraw-Events erkennen

Über das requestAnimationFrame-API kann erkannt werden, wenn Links erneut dargestellt werden. Aber nur, wenn das länger als 16 ms dauert. Ist die Änderung in weniger als 16 ms erledigt, sinkt die Frame-Rate nicht und die Änderung bleibt unerkannt. Und das ist bei den aktuellen, stark optimierten Browsern, die viele Grafikoperationen an die GPU auslagern, durchaus möglich. Um Redraws erkennen zu können, muss das Link-Rendering also so weit verlangsamt werden, dass es länger als 16 ms dauert und dadurch die Frame-Rate senkt.

Paul Stone verwendet dazu die CSS Property text-shadow [5], mit der verschiedene Effekte auf einen Text angewendet werden können. Die für das Rendering eines Texts mit text-shadow benötigte Zeit ist proportional zum Wert des blur-radius – je größer der blur-radius, desto länger dauert das Rendering. Mit diesen Vorarbeiten ist es möglich, besuchte Links zu erkennen.

History Sniffing bei asynchronem URL-Lookup

  1. Eine Webseite enthält eine Anzahl von Links mit angewendetem text-shadow, die alle zum gleichen URL verweisen.
  2. Die für die Darstellung der nächsten n Frames benötigte Zeit wird über das requestAnimationFrame-API ermittelt.
  3. Die ermittelten Werte werden analysiert, um festzustellen, ob ein Redraw erfolgt ist.

Paul Stone hat für n den Wert 5 gewählt. Im Firefox dauert der Aufbau der ersten beiden Frames ca. 90 bis 150 ms. Bei zuvor bereits besuchten Links braucht auch der dritte Frame so lange. Alle anderen Frames werden schneller gezeichnet (siehe Tabelle 2.1, basierend auf den Daten von Seite 9 im Whitepaper zu [3], der Frame mit dem Redraw des zuvor besuchten Links ist fett hervorgehoben).

Link\Frame #

1

2

3

4

5

www.facebook.com

(bereits besucht)

106

155

186

3

16

www.google.com

(bereits besucht)

95

152

193

11

16

www.youtube.com

(nicht besucht)

93

143

15

26

7

www.twitter.com

(nicht besucht)

126

150

8

16

16

Tabelle 2.1: Timing der Frames im Firefox

Kalibrierung macht den Angriff universell

Da die Dauer des Redraw vom Rechner abhängig ist, auf dem der Browser läuf...

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

Angebote für Gewinner-Teams

Wir bieten Lizenz-Lösungen für Teams jeder Größe: Finden Sie heraus, welche Lösung am besten zu Ihnen passt.

Das Library-Modell:
IP-Zugang

Das Company-Modell:
Domain-Zugang