SSL Pinning und Android

Wenn Apps über das Internet kommunizieren, verschlüsseln heute alle seriösen App-Entwickler ihre Daten per SSL (das war nicht immer so). Und das ist sehr sinnvoll, nicht nur um Zuge der NSA-Enthüllungen der letzten Monate. Niemand möchte, dass beispielsweise die eigenen Google-Suchanfragen für jeden im freien WLAN des Cafés nebenan mitlesbar sind. Nicht selten sind diese äußerst privater Natur.

Trotzdem sind viele kleine Details zu beachten, damit SSL sinnvoll und nicht falsch angewandt wird. Und hier spielt SSL Pinning eine wichtige Rolle.

SSL Pinning

Mit SSL Pinning gibt man dem Client (in unserem Fall ist dies die App) fest vor, welches Zertifikat er auf dem Server zu erwarten hat. Findet er ein anderes Zertifikat vor, wird die Verbindung nicht akzeptiert. Ein großer Vorteil bei Entwicklung von Apps ist der Fakt, dass man wieder Kontrolle über den Client bekommt, und nicht nur über den Server. So kann man im Client das auf dem Server zu erwartende Zertifikat fest definieren und damit jedes andere (böse) Zertifikat ausschließen. Bei Webapplikationen ist die Kontrolle des Browsers des Users je nach Kundenstamm deutlich schwerer bis unmöglich.

SSL Pinning bringt nun gleich mehrere Vorteile:

  • Man-In-The-Middle-Angriffe sind nicht möglich, da dem Nutzer gar kein falsches Zertifikat untergeschoben werden kann. Es wird im Code, und nicht über eine Auswahl des Users, genau ein gegebenes Zertifikat akzeptiert. Andere Zertifikate werden abgelehnt.
  • Probleme mit kompromittierten Root-Zertifikate sind ausgeschlossen (was schon öfter der Fall war, als man annehmen sollte).
  • Angreifer können (ihren eigenen) Traffic zwischen der App nicht analysieren, um damit eventuell bisher unbekannte Lücken zu finden oder mit gefälschten Anfragen Exploits zu finden. Mit Tools wie dem mitmproxy sind Analysen dieser Art in Browsern sehr einfach durchzuführen.

SSL Pinning für Android

Für Android Apps ist SSL Pinning recht einfach umzusetzen. Hier eignet sich das exzellente Library Project AndroidPinning von Moxie Marlinspike. Dieser Weg ist vor allem dann interessant, wenn man auf ein von einer CA signiertes Zertifikat angewiesen ist, weil man z.B. ein gemeinsames Zertifikat mit dem Webfrontend teilt. Ohne diesen Constraint wäre es natürlich auch möglich, komplett auf CA-signierte Zertifikate zu verzichten und eigene Zertifikate zu erstellen und die CA Chain damit komplett zu umgehen. Dieser Weg mag sogar der sicherere sein, ist aber nicht immer praktikabel.

Wir clonen zuerst die Library via git:

git clone https://github.com/moxie0/AndroidPinning

und binden das Library Project wie gewohnt in unsere App ein. Hilfe bieten hier auch die Android Developer Docs.

Dann benötigen wir eine Information im Zertifikat, die wir pinnen können. Hier eignet sich die SubjectPublicKeyInfom, die wir wie folgt aus dem entsprechenden Zertifikat extrahieren:

$ tools/pin.py dein-cert.pem
Calculating PIN for certificate: O=api.cortex-media.de, OU=Go to https://www.thawte.com/repository/index.html, OU=Thawte SSL123 certificate, OU=Domain Validated, CN=api.cortex-media.de
Pin Value: 425c3f8c27c44ab1e0818812cb7115e30140a31b

(oder alternative auch eine .crt Datei, je nachdem was vorliegt.)

Der PIN Value ist die Informationen, die wir in den nachfolgenden Schritten in der Android App hart verdrahten. Im unteren Beispiel nutzen wir die „425c3f8c27c44ab1e0818812cb7115e30140a31b“ als Beispiel für eine PIN.

Wenn für die HTTP Kommunikation via HttpClient gearbeitet wird, kann der Client wie folgt initialisiert werden:

String[] pins          = new String[] {"f30012bbc18c231ac1a44b788e410ce754182513"};
HttpClient httpClient  = PinningHelper.getPinnedHttpClient(context, pins);
HttpResponse response  = httpClient.execute(new HttpGet("https://www.google.com/"));

Für die HttpsUrlConnection läuft die Initialisierung nahezu analog ab:

String[] pins          = new String[] {"425c3f8c27c44ab1e0818812cb7115e30140a31b"};
URL url                = new URL("https://www.google.com");
HttpsURLConnection con = PinningHelper.getPinnedHttpsURLConnection(context, pins, url);

Und das wäre dann auch schon alles: Kein anderes Zertifikat als angegebene wird akzeptiert und die SSL Kommunikation ist ein Stück weit sicherer.

In Technischer Hintergrund veröffentlicht | Getaggt: ,

Die perfekte SSL Cipher Suite für Apache (und andere)

„SSL ist nicht mehr sicher!“ konnte man in den letzten Wochen das ein oder andere mal in den einschlägigen Nachrichtenmagazinen lesen. Aber stimmt das? Wir denken nicht.

Es ist korrekt, dass manche der von SSL verwendeten Verschlüsselungsalgorithmen nicht (mehr) stark genug sind (z.B. RC4) oder als von der NSA kompromittiert vermutet werden. Aber das gilt nicht für alle. Vor allem nicht für die mathematischen Grundlagen, die hinter den Algorithmen stecken.

Wer einen Apache Webserver mit SSL betreibt, und unter allen Cipher-Suiten die schwarzen Schafe ausschließen, Perfect Forward Secrecy aktivieren und damit deutlich an Sicherheit gewinnen will, kann sich mit der folgenden Direktive von allen Algorithmen verabschieden, die als nicht (mehr) sicher gelten.

Für den Apache sieht dies wie folgt aus, für Nginx analog, da die Syntax für die Auswahl der Suiten analog läuft.

SSLEngine On
SSLProtocol all -SSLv2
SSLHonorCipherOrder On
SSLCipherSuite EECDH+ECDSA+AESGCM:EECDH+aRSA+AESGCM:EECDH+ECDSA+SHA256:EECDH+aRSA+RC4:EDH+aRSA:EECDH:!RC4:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS
In Technischer Hintergrund veröffentlicht | Getaggt: ,