~/blog/2011/10/diginotar-zertifikate-truststores.md

DigiNotar-Hack: Zertifikate und Truststores in Java

3 min
Titelbild: DigiNotar-Hack: Zertifikate und Truststores in Java

Keine Zeit? Hier die Kurzversion in 30 Sekunden.

  • Die niederländische CA DigiNotar wurde gehackt, gefälschte Zertifikate (u. a. für google.com) tauchten Ende August 2011 auf. Im September ging die Firma in Konkurs.
  • Browser und Oracle haben DigiNotar das Vertrauen entzogen; bei Java kommt das über ein JRE-Update.
  • Die vertrauenswürdigen CAs stehen in der Datei cacerts im JRE, ansehen und ändern geht mit keytool.
  • Ein eigener Truststore lässt sich per -Djavax.net.ssl.trustStore setzen, ohne die JRE-Dateien anzufassen.
  • Einen TrustManager zu bauen, der alles akzeptiert, ist keine Lösung für Zertifikatsfehler, sondern schaltet die Absicherung ab.

Der Fall DigiNotar hat im Spätsommer ziemlich Wellen geschlagen. Die niederländische Zertifizierungsstelle wurde gehackt, und Ende August tauchten gefälschte Zertifikate auf, unter anderem für google.com. Wer ein solches Zertifikat hat und den Datenverkehr eines Opfers umleiten kann, kann sich als die echte Seite ausgeben, und der Browser meldet nichts, weil die CA ja als vertrauenswürdig gilt. Die Browserhersteller haben DigiNotar daraufhin das Vertrauen entzogen, und auch Oracle hat die Java-Runtime per Update angepasst. DigiNotar selbst ist im September in Konkurs gegangen.

Mich hat das zum Anlass genommen, mir mal wieder anzusehen, wie Java eigentlich entscheidet, welchen Zertifikaten es traut. Das Thema ist gar nicht so kompliziert.

Wo Java den CAs vertraut

In jeder JRE liegt eine Datei namens cacerts, ein Keystore mit den Zertifikaten der Wurzel-CAs. Bei Java 6 findet ihr sie unter JAVA_HOME/jre/lib/security/cacerts. Das Standardpasswort ist changeit. Auflisten geht mit keytool:

keytool -list -keystore cacerts -storepass changeit

Mit der Ausgabe lässt sich filtern, ob etwas Verdächtiges drin ist (unter Windows statt grep einfach findstr /i):

keytool -list -keystore cacerts -storepass changeit | grep -i diginotar

Mit -v bekommt ihr zu jedem Eintrag Aussteller, Gültigkeit und Fingerabdruck. Wie die Aliase heißen, solltet ihr bei euch selbst nachsehen und nicht raten, die Namen unterscheiden sich je nach Java-Version.

Ein Zertifikat entfernen

Wenn ein Eintrag raus soll, geht das mit dem Alias:

keytool -delete -alias aliasname -keystore cacerts -storepass changeit

Das ändert die Datei der installierten JRE, ihr braucht also entsprechende Rechte. Außerdem kann ein Java-Update die Datei wieder überschreiben. Für den Fall DigiNotar ist das Update von Oracle der bessere Weg. Wer ohnehin eine Anwendung ausliefert, die ihre Verbindungen selbst absichert, ist mit einem eigenen Truststore oft besser dran.

Eigener Truststore

Statt die cacerts des Systems zu verändern, kann man einen eigenen Truststore anlegen und die JVM darauf zeigen lassen. Ein Zertifikat (hier eine Datei meineca.crt) importiert ihr so:

keytool -import -trustcacerts -alias meineca -file meineca.crt -keystore meintruststore.jks

Gestartet wird die Anwendung dann mit:

java -Djavax.net.ssl.trustStore=meintruststore.jks -Djavax.net.ssl.trustStorePassword=geheim -jar anwendung.jar

Wichtig: Der Truststore ersetzt dann komplett die Standardliste. Vertraut wird nur noch, was in der Datei steht. Für interne Server mit einer eigenen CA ist das praktisch, für Verbindungen ins normale Internet müsst ihr die nötigen CAs selbst mit hineinkopieren.

Bitte nicht: alles akzeptieren

Wer mit selbst signierten Zertifikaten in der Testumgebung arbeitet, stößt irgendwann auf eine SSLHandshakeException, und im Netz findet man dazu schnell Code, der einen TrustManager baut, der einfach alles durchwinkt, oft zusammen mit einem HostnameVerifier, der immer true zurückgibt. Das funktioniert, ist aber genau das, was DigiNotar so gefährlich gemacht hat, nur freiwillig: Jede gefälschte Gegenstelle wird akzeptiert. Wenn so etwas einmal im Testcode steht, ist es erfahrungsgemäß schnell auch im Produktivcode.

Besser ist es, das selbst signierte Zertifikat in einen Truststore zu importieren wie oben. Dann bleibt die Prüfung aktiv und die Verbindung klappt trotzdem.

Auch die Hostname-Prüfung sollte man nicht abschalten. Sie stellt sicher, dass das Zertifikat auch wirklich zum Server gehört, mit dem ihr gerade redet. Bei HttpsURLConnection läuft sie standardmäßig mit. Ein gültiges Zertifikat für irgendeine andere Domain nützt einem Angreifer sonst genauso viel wie ein gefälschtes.

Habt ihr bei euch mal in die cacerts geschaut? Ich fand es ganz aufschlussreich, wie viele Einträge da liegen. Bis zum nächsten Mal!

Beitragsbild: eigene Collage mit Logos von Wikimedia Commons (DigiNotar-Logo (2008): DigiNotar, gemeinfrei); die Marken gehören ihren Inhabern.

$ whoami
Christian Ackermann

Softwareentwickler (C++, C, Java, C#) aus der Oberpfalz, bloggt seit 2001 über Linux, Technik und Kochen.