Das W3C Web Cryptography API – Sinnvoll oder Nicht

Seit einiger Zeit arbeitet eine Arbeitsgruppe des W3C an der „Web Cryptography API“ (http://www.w3.org/TR/WebCryptoAPI/). Ziel ist eine standardisierte Schnittstelle, mit deren Hilfe kryptographische Operationen mittels JavaScript ermöglicht werden.

JavaScript-Kryptographie, oder vielleicht sogar allgemeiner JavaScript-Security, genießen traditionell einen eher schlechten Ruf. Im berühmten Artikel „JavaScript cryptography considered harmful“ (http://matasano.com/articles/javascript-cryptography/) findet man die Argumente gegen ein solches Unterfangen prägnant zusammengefasst.

Einer der Hauptgründe des Artikels gegen JavaScript-Kryptographie ist das Henne-/Ei-Problem, mit dem man zwangsläufig konfrontiert wird. Wenn der JavaScript-Code über eine ungeschützte HTTP-Verbindung an den Browser geschickt wird, besteht immer die Gefahr eines „Man-in-the-Middle“, d.h. ein potenzieller Angreifer könnte unbemerkt in die Kommunikation zwischen Server und Browser eingreifen und vom Server gelieferte Ressourcen (HTML, JS, …) nach Belieben anpassen und austauschen.

JavaScript-Kryptographie ist nicht „sicherer“ als die traditionelle serverseitige Kryptographie

Die derzeit einzige Möglichkeit, dies mit ausreichender Sicherheit zu unterbinden, besteht darin, den gesamten Datenverkehr zwischen Server und Browser mittels TLS abzusichern – d.h. strikt https anstatt http zu verwenden. Doch selbst dann, wenn die sichere Kommunikation des JS-Codes gewährleistet ist, ist man trotzdem als Browser-Nutzer darauf angewiesen, dem Server zu vertrauen: Letztendlich kommt das JavaScript, das im Browser ausgeführt wird, vom Server. Niemand kann garantieren, dass dieser Code korrekt ist und im Sinne des Benutzers agiert. Somit erscheint JavaScript-Kryptographie auf den ersten Blick nutzlos: Wenn man sowieso dem Server vertrauen muss, wieso lässt man ihn dann nicht gleich die kryptographischen Operationen komplett serverseitig erledigen, wie man das schon seit jeher macht?

Dieser Einwand ist berechtigt, und gleich vorweg: Es gibt keine Möglichkeit, diese Klippe mit JavaScript-Kryptographie zu umschiffen. JavaScript-Kryptographie ist nicht „sicherer“ als die traditionelle serverseitige Kryptographie. Im Gegenteil, um ein vergleichbares Maß an Sicherheit zu erhalten, müssen eine Reihe an Vorkehrungen getroffen werden, z.B., dass der JS-Code ausschließlich via https geliefert wird. Und dann ist da noch die Tatsache, dass sich JavaScript lange Zeit als ziemlich unhandlich erwiesen hat, wenn es um die Umsetzung kryptographischer Funktionen geht. Es gibt keine native Unterstützung, um mit Binärdaten zu arbeiten, die Unterstützung für Encodings wie etwa UTF-8 oder Base64 ist dürftig, und auch, wer mit großen Ganzzahlen arbeiten möchte, sieht sich vor ein Problem gestellt.

Verschlüsselung braucht einen sicheren Zufallszahlengenerator

All diese Sachen sind aber dringend notwendig, um mit Verschlüsselung oder digitalen Signaturen vernünftig arbeiten zu können. Am schlimmsten wiegt der Umstand, dass JavaScript von Haus aus keinen kryptographisch sicheren Zufallszahlengenerator zur Verfügung stellt. Im Gegensatz zu einfachen Zufallszahlengeneratoren wie etwa dem eingebauten Math.random braucht es für die Kryptographie besondere Generatoren. Bei „normalen“ Generatoren ist es Angreifern möglich, durch genügend observierte Zufallszahlen künftigen Output vorherzusagen. Dies ist fatal für kryptographische Verfahren, die allesamt früher oder später ein zufällig erzeugtes Element benötigen, z.B. den Schlüssel bei Verschlüsselungsverfahren. Vereinfacht gesagt, verkommt jegliches Verfahren zu einer Farce, wenn kein kryptographisch sicherer Generator zur Verfügung steht. Man muss gar nicht erst die Verfahren selbst angreifen, da man mit weniger Aufwand die Schlüssel vorhersagen kann.

Die Vorteile des W3C Web Cryptography API

Und genau hier setzt das Web Cryptography API ein. Es bietet mit window.crypto.getRandomValues einen kryptographisch sicheren Zufallszahlengenerator, der somit das Tor für „echte“ Kryptographie mit JavaScript im Browser öffnet. Doch warum sollte man sich das antun wollen? Wo wir doch gesehen haben, dass wir letzten Endes keinen Schritt weiter sind als zuvor? Also was bringt uns das Ganze? Als Browser-Nutzer müssen wir weiterhin den Servern und den Anbietern, die sie betreiben, vertrauen, und daran lässt sich auch nichts ändern. Doch wenn wir dies tun und davon ausgehen, dass die Betreiber von Angeboten zu unseren Gunsten handeln (nichts Anderes tun wir derzeit, wenn wir das Angebot eines beliebigen Anbieters nutzen), so bieten sich doch einige Vorteile.

Das Problem: Klartextspeicherung trotz verschlüsselter Übertragung

Zum Beispiel nehmen wir momentan billigend in Kauf, dass unsere Passwörter im Klartext auf den Servern der Betreiber lesbar sind. Sicher, die Passwörter werden in der Regel über TLS verschlüsselt an die Server verschickt, doch nach der Entschlüsselung liegen sie auf dem Server im Klartext vor. Wir vertrauen hier dem Betreiber der Seite, dass er keinen Unfug mit unseren Daten anstellt. Vorbildliche Implementierungen speichern unsere Passwörter dann auch ihrerseits nicht im Klartext, sondern merken sich nur einen aufwendig berechneten Hash des Passworts (z.B. mit PBKDF2 (http://de.wikipedia.org/wiki/PBKDF2), bei dessen Verlust es Angreifern nahezu unmöglich ist, auf das eigentliche Passwort zu schließen. Und doch bietet sich Angreifern die Möglichkeit, diesen kurzen Moment auszunutzen, in dem das Passwort im Klartext im Speicher des Servers vorliegt. Würde der Passwort-Hash stattdessen bereits clientseitig im Browser berechnet, böte sich diese Gelegenheit nicht. Ein Angreifer müsste fortan gezielt einzelne Benutzer angreifen, um an deren Passwörter zu gelangen, würde aber nicht auf einen Schlag alle Passwörter erhalten, sobald der Server kompromittiert ist. Der Hash muss in diesem Szenario zwar nach wie vor via TLS verschlüsselt übermittelt werden, da er jetzt quasi den Part des Passworts übernimmt, und doch hat man etwas gewonnen: Das Passwort liegt zu keiner Zeit mehr im Klartext auf dem Server vor. Dies schützt beispielsweise solche User besser, die das gleiche Passwort bei mehreren Diensten verwenden. Das eigentliche Passwort bleibt für Angreifer unzugänglich und kann somit nicht mehr ohne Weiteres bei anderen Diensten wiederverwendet werden.

Vor-Verschlüsselung von Daten

Die Skandale in jüngster Vergangenheit haben gezeigt, dass Betreiber von Internetdiensten mehr oder minder machtlos sind, wenn höhere Instanzen an die Tür klopfen, um sich Einblick in die Daten zu verschaffen. Auch wenn der Dienst absolut vorbildlich in punkto Sicherheit implementiert ist, werden in der Regel vertrauliche Daten beim Dienst z.B. in einer Datenbank im Klartext gespeichert. Der einzige Weg, wie sich ein User gegen diese Art von Eingriff in die eigene Privatsphäre schützen kann, besteht darin, die Daten bereits zu verschlüsseln, bevor sie den eigenen Rechner/Browser verlassen. Die Umsetzung scheitert aber oft daran, dass entsprechende Tools zu kompliziert und zu umständlich sind. Zudem besteht leicht die Gefahr, aus Unwissenheit etwas falsch zu machen, so dass die sicher geglaubten Daten in den Händen versierter Angreifer leicht zu dechiffrieren sind.

Web Cryptography API erlaubt die Vor-Verschlüsselung der Daten

Hier bietet das Web Cryptography API eine Riesenchance für Anbieter. Sie können den Benutzern unter die Arme greifen, indem sie ihnen transparent und ohne weiteres Zutun die entsprechende Funktionalität zur Verfügung stellen. Man stelle sich etwa eine Dropbox vor, was die Dateien clientseitig verschlüsselt und nur in verschlüsselter Form auf den eigenen Servern ablegt. Die Ver- und Entschlüsselung läuft transparent im eigenen Browser ab. Für den Benutzer bietet sich das gleiche Erlebnis, die Privatsphäre ist aber erheblich besser geschützt, da die verschlüsselten Daten beim Betreiber nicht länger einsehbar sind.

Neben vielen weiteren positiven Beispielen gibt es auch wesentlich pragmatischere Gründe für JavaScript-Kryptographie. So ist bei einer HTML5-Anwendung unter Umständen gar kein Server mehr da, der den Kryptographie-Part übernehmen könnte. Das heißt aber noch lange nicht, dass man auf Kryptographie verzichten möchte. Man denke nur etwa an Daten, die in einem HTML5 Local Storage auf einem Mobiltelefon gespeichert werden.

Zusätzlich zum Schutz der Privatsphäre von Benutzern haben aber auch die Betreiber selbst Interesse an Kryptographie im Browser. Sie versprechen sich sichere DRM-Verfahren, um Inhalte zugänglich zu machen, ohne aber die Möglichkeit zu bieten, diese einfach kopieren zu können. Als Beispiele dienen urheberrechtlich geschützte Bilder, E-Books oder Videos/Filme (Netflix ist prominentes Mitglied der W3C-Arbeitsgruppe).

Web Cryptography API in der Praxis

Ich hoffe, Ihnen das Thema ein wenig schmackhaft gemacht zu haben. Wenn Sie noch mehr über die Gründe und Hintergründe des Web Cryptography API erfahren und Code für die Umsetzung konkreter Beispiele sehen möchten, lade ich Sie herzlich zu meinem Vortrag über das Thema bei der IT-Security-Konferenz der GFU Cyrus AG am 27.11.2014 in Köln (https://it-security-konferenz.de/) ein!