Android-Updates und TLS-Verbindungen

Android-Gerätehersteller sind bekannt für ihre kurzen Support-Zeiträume. Sie bieten nur für eine begrenzte Zeit Updates an oder liefern sogar Geräte mit alten Android-Versionen aus. Entwickler haben sich so mit einer zersplitterten Verteilung von Android-Versionen auseinanderzusetzen. Android 4.x wird noch immer von ungefähr 2% der auf Google Play aktiven Geräte verwendet. Alte Telefone haben für gewöhnlich noch ordentliche Leistungsreserven und nach einem Update auf ein Custom-ROM sind sie sogar bis zum heutigen Tag bestens ausgestattet. Unglücklicherweise gibt es nicht für alle Geräte Custom-ROMs und nicht alle Anwender wollen sich mit den möglichen Schwierigkeiten beschäftigen, die deren Installation mit sich bringen kann.

AntennaPod ist ein, von mir betriebener, quelloffener Podcast-Manager für Android. AntennaPod hängt nicht von einem zentralen Server ab, sondern holt sich die Podcast-Quellen direkt über das Gerät. Zum Schutz der Nutzerdaten ziemlich nett, weil niemand eine komplette Liste der Abos erhält. Leider stoßen mehr und mehr Nutzer alter Android-Versionen auf Probleme mit bestimmten Podcast-Feeds. Der Grund dafür ist, dass Server Updates auf aktuellere TLS-Versionen erhielten, die auf den Geräten nicht zur Verfügung stehen. Eine Aktualisierung der TLS-Version auf Servern ist definitiv etwas Gutes, da es die Kommunikation sicherer macht. Die meisten Browser bringen deshalb ihren eigenen Stack mit, der ihnen ein Update unabhängig vom Gerätehersteller ermöglicht. Leider kommt es bei allen anderen Apps, wie AntennaPod, die von Verbindungen zu mehreren Servern außerhalb ihrer Kontrolle abhängen, zu Problemen. Anwender finden dann Download-Fehler wie folgenden: Failure in SSL Library, usually a protocol error. Das ist ziemlich schlecht, da sie Nutzer daran hindern, Podcasts zu hören. Obwohl dies im Grunde ein Versagen der Gerätehersteller ist, fällt es letztlich auf die App-Entwickler zurück.

Die Unterstützung von TLSv1.1 und TLSv1.2 begann mit Android 4.1 und wurde Standard in Android 5.0. Es gibt auch eine Anzahl von Cipher-Suites und Zertifikaten, die in Android 4.x nicht unterstützt werden. Auch wenn dieses Problem momentan nur Android-4.x-Nutzer betrifft, werden in Zukunft weitere folgen, nachdem Server auf TLSv1.3 aktualisiert wurden. TLSv1.3 wurde zum ersten Mal mit Android 10 ausgeliefert, das auf ungefähr 8% der auf Google Play angemeldeten Geräte läuft. Einzelheiten zur SSL-Unterstützung in Android findet man auf der SSLSocket reference page. Die Entwickler haben sich nun mit der Tatsache auseinanderzusetzen, dass Hersteller Software-Updates vernachlässigen.

Dies ist ein bekanntes Problem, also hat Google eine mit ProviderInstallerbenannte Bibliothek veröffentlicht. Sie ist wirklich einfach anzuwenden (ProviderInstaller.installIfNeeded(context);) und behebt all diese Probleme augenblicklich. Weil der Provider mittels der Google Play Services unabhängig von der App auf dem neuesten Stand bleibt, müssen sich App-Entwickler darum nicht mehr kümmern.

Das klingt zu schön um wahr zu sein, oder? Schön, Googles ProviderInstaller hat einen gewichtigen Nachteil. Die Bibliothek ist nicht quelloffen, also kann sie nicht für Apps genutzt werden, die auf F-Droid veröffentlicht werden. AntennaPod wird momentan in zwei verschiedenen Varianten hergestellt: eine ist 100% freie Software für F-Droid und eine mit der ProviderInstaller-Bibliothek für den Google Play Store. Dies bedeutet, dass F-Droid-Nutzer außen vor bleiben. Sie erleben weiterhin Verbindungsprobleme bei manchen Servern und betrachten diese als einen Bug in AntennaPod.

Eine Alternative, die mit F-Droid funktioniert, ist die Aufnahme der quelloffenen Bibliothek Conscrypt. Das Einbinden von Conscrypt ist genau so einfach wie die Verwendung von Googles ProviderInstaller, aber es hat zwei wichtige Nachteile:

  • App-Entwickler sind gezwungen, regelmäßig den Provider zu aktualisieren. Das bedeutet zusätzliche Arbeit für die Betreiber und kann bei Apps, die einen langsamen Entwicklungszyklus haben, Ärger machen.
  • Die Einbindung von Conscrypt erhöht die APK-Größe. Im Fall von AntennaPod bedeutet das, dass die App ungefähr 4 MB größer wird, was eine Zunahme von 40% bedeutet, für eine weitestgehend unsichtbare Änderung. Zu berücksichtigen ist, dass jede App dies tun müsste, um einen aktualisierten TLS-Stack zu erhalten. Wenn jede App auf F-Droid, die Verbindungen ins Netz herstellt, zusätzlich 4 MB TLS-Bibliotheken einbinden müsste, würde dies zu einer beachtlichen Erhöhung der Speicherauslastung führen.

Glücklicherweise gibt es dafür eine Lösung! Der Plan ist, eine quelloffene Provider-Anwendung zu schreiben (so wie eben Googles Provider), die nichts anderes tut, als Conscrypt einzubinden und eine stabile API bereitzustellen, die es anderen Apps ermöglicht es zu laden. Sie kann dann unabhängig von Apps wie AntennaPod oder F-Droid aktualisiert werden. Die Provider-App könnte einfach eine Klasse besitzen, in etwa so wie hier:

public static void install() {
    Security.insertProviderAt(Conscrypt.newProvider(), 1);
    Log.d(TAG, "Provider installed.");
}

Wir könnten dann eine quelloffene Bibliothek entwickeln, die den ClassLoader nutzt, um die Conscrypt-Bibliothek aus der Provider-App einzuschließen.

Context targetContext = context.createPackageContext("com.bytehamster.providerinstaller",
        Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
ClassLoader classLoader = targetContext.getClassLoader();
Class installClass = classLoader.loadClass("com.bytehamster.providerinstaller.ProviderInstallerImpl");
Method installMethod = installClass.getMethod("install", new Class[]{ });
installMethod.invoke(null);
installed = true;

Programmtextbeispiele sind (etwas detaillierter) auf GitHub Gist abrufbar.

Klar, einfach Code aus einer anderen App einschließen, stellt ein Sicherheitsrisiko dar. Durch Einschluss des Providers führt man fremden Code im eigenen App-Kontext aus. Wie kann man nachweisen, dass der Provider nicht böswillig ist? Es gibt ein paar Verfahren, um zu überprüfen, dass dem Provider vertraut werden kann:

  • Eine vertrauenswürdige App kann der Provider sein. Die F-Droid-App selbst könnte den Provider einbinden, ihn auf dem neusten Stand halten und die stabile API bereitstellen. Apps könnten dann den Paketnamen von F-Droid fest programmieren und dessen Signatur überprüfen. Das Problem bei diesem Ansatz ist, dass Anwender, die F-Droid selbst kompilieren oder Alternativen wie G-Droid verwenden, nicht die aktualisierten Bibliotheken nutzen könnten.
  • Die Programmbibliothek könnte das Android-System nach kompatiblen Conscrypt-Provider-Apps durchsuchen und eine von ihnen einschließen. Um sicherzustellen, dass dies sicher ist, wäre es möglich den Provider nur einzuschließen, wenn es sich um eine System-App handelt. So könnte die F-Droid-Rechteerweiterung Conscrypt einbinden und bereitstellen. Viele F-Droid-Anwender nutzen allerdings die Rechteerweiterung nicht, somit würden wir immer noch nicht alle Anwender erreichen.
  • Für mich scheint die beste Lösung, eine eigenständige App (wie org.fdroid.securityprovider) zu sein, die Conscrypt bereitstellt. Das wurde auch im F-Droid-Forum so diskutiert und ursprünglich von @bubu vorgeschlagen. Eine vertrauenswürdige Entität wie F-Droid könnte den Provider herstellen und mit ihren Schlüsseln signieren. Diese könnten dann durch die aufrufenden Apps, die Conscrypt einbinden möchten, verifiziert werden.

Ich sähe es sehr gerne, wenn es sich in diese Richtung bewegen würde. Wir sollten unbedingt die Möglichkeiten einer vollständig quelloffenen, sicheren Provider-App ausloten. Leider bin ich mit dem Betrieb von AntennaPod ziemlich beschäftigt. Daher kann ich mich nicht um die Programmbibiothek und Installationsanwendung kümmern. Auf GitHub Gist liegt eine Machbarkeitsstudie vor, der aber Sicherheitsprüfungen fehlen. Es wäre wahrscheinlich auch gut, einige einfache Verfahren zu ergänzen, die Anwender darauf hinweisen, den Provider bei TLS-Fehlern zu installieren. Wer Interesse an der Erstellung eines quelloffenen Providers hat, sollte einen Blick ins F-Droid Forum werfen.

Einige Anmerkungen:

  • Dieser Post wurde aus der Sicht eines App-Entwicklers geschrieben. Ich versuche, AntennaPod so zu gestalten, dass es für alle Anwender optimal funktioniert, einschließlich derjenigen mit Android 4.x. Aus der Anwenderperspektive sollte man darüber nachdenken, ob man alte Android-Versionen wie 4.x noch verwenden will. Android 4.4 wurde 2014 veröffentlicht, was 6 Jahre her ist. Viele kritische Sicherheitslücken wurden seither geschlossen. Ein so altes Gerät ins Internet zu lassen, kann ein ziemlich großes Sicherheitsrisiko sein, unabhängig davon, welche TLS-Bibliotheken in den Apps eingebunden sind.
  • Bevor ich mich hiermit beschäftigt habe, wusste ich nicht, dass man ClassLoader nutzen kann, um den Code einer anderen App auszuführen. Das ist ziemlich nett und kann für Dinge wie Plugins verwendet werden. Ich würde gerne erfahren, was andere Entwickler damit erstellen.