Zusätzliche APK-Checks im IzzyOnDroid Repo
Wir verwenden Apps, weil wir ihre Funktionalität schätzen. Aber manchmal enthalten sie auch Komponenten, die wir selbst nicht ausgewählt hätten, wenn man uns gefragt hätte. Teile des Codes, die entweder für die geschätzte Funktionalität der App nicht benötigt werden (wie Werbung oder Tracker) – oder Module, die nicht FOSS sind, wodurch die FOSS-App zu einer „befleckten“ App wird, die streng genommen nicht mehr FOSS ist. Zwei frühere Artikel auf dieser Seite geben einige Einblicke in diese Problematik:
- Was hat es mit den Modulen in Android Apps auf sich? (2017-04-22)
- Module in Apps identifizieren (2021-01-29)
Der im IzzyOnDroid repo verwendete LibraryScanner, welchen der letztgenannte Artikel beschreibt und der unter einer FOSS-Lizenz verfügbar ist, macht transparent, welche Bibliotheken/Module eine APK-Datei enthält. Ein Überblick über die aktuell im IzzyOnDroid Repo eingesetzten Maßnahmen findet sich im Abschnitt What about security? in der Info-Seite des Repos.
Im Januar 2024 wurden zusätzliche Sicherheitsmaßnahmen für das IzzyOnDroid Repository eingeführt. Sie sollen in diesem Artikel nicht nur vorgestellt werden, sondern auch ein paar Hintergrundinformationen erhalten.
Scans des AndroidManifests
Wikipedia beschreibt den Begriff „Manifest“ eingangs wie folgt:
Ein Manifest (von lateinisch manifestus ‚handgreiflich gemacht‘, ‚offenbart‘) ist eine öffentliche Erklärung von Zielen und Absichten

AndroidManifest.xml
In der Anwendungsprogrammierung gibt es etwas ähnliches: die Manifest Datei. Android-Apps enthalten in der Regel gleich mehrere Manifeste in ihrer APK Datei, von der uns an dieser Stelle hauptsächlich eine Datei namens AndroidManifest.xml
interessieren soll. In dieser werden sozusagen die Ziele und Absichten der zugehörigen App deklariert:
- Name und Version der App
- welche Berechtigungen sie verlangt
- welche Komponenten (Aktivitäten, Services etc.) sie bereitstellt
- und einiges mehr
In der APK Datei selbst liegt dieses AndroidManifest.xml
in binärer Form („AXML") vor, das sich aber z. B. mittels androguard axml <datei.apk>
extrahieren und sodann analysieren lässt. Dies geschieht für jede APK-Datei, die in das IzzyOnDroid-Repositorium gelangt, wobei die folgenden Prüfungen durchgeführt werden:
Überprüfen von Flags
Das AndroidManifest definiert Application Elements, welche ich hier kurz als „Flags“ bezeichnen möchte. Diese sagen einiges über das Verhalten der App aus, und es gibt eine ganze Reihe davon – etwa in welche Kategorie eine App gehört, ob sie Backups ihrer Daten erlaubt, mit welchem Icon sie im App-Drawer präsentiert werden möchte, und mehr. Für das Thema „Sicherheit und Privatsphäre“ wären davon hauptsächlich drei Flags interessant und daher bei Scans berücksichtigt:
android:debuggable
: fdroidserver (die hier für die Erstellung der Repository-Struktur und die Erstellung des Indexes mit den verfügbaren Apps zum Einsatz kommt) prüft dies bereits und gibt eine Warnung aus, woraufhin der Updater eine E-Mail-Benachrichtigung an mich sendet. Dies ist sozusagen ein zweischneidiges Schwert. Auf der einen Seite ermöglicht dieses Flag es uns, die Anwendungsdaten der App auch unter Android 12 zu sichern – andererseits stellt es auch ein gewisses Sicherheitsrisiko dar, da sich mit Debug-Informationen teilweise auch sensible Dinge auslesen ließen, auf die man sonst von Außen keinen Zugriff hätte. Was natürlich haupsächlich dann relevant wird, wenn Dritte Euer Gerät in die Finger bekommen.
Dieses Flag ist für die Phase der App-Entwicklung gedacht. Normalerweise sollte eine App, die für die Weitergabe gedacht ist, es daher nicht aufweisen. Hat der Entwickler dies vergessen, gibt es vielleicht auch noch andere „vergessene Dinge“ bzw. die App war eigentlich (noch) gar nicht zur Verteilung gedacht. Daher ist unklar, ob dieses Flag als Risiko gewertet werden sollte oder als Feature. Derzeit führt es dazu, dass die App mit dem entsprechenden „Anti-Feature“ (ApplicationDebuggable
) bedacht wird.android:testOnly
Dieses Flag ähnelt start dem vorigen. Die Dokumentation schreibt dazu, grob übersetzt: „Dieses Attribut gibt an, ob diese Anwendung nur zu Testzwecken dient. Sie könnte beispielsweise Funktionen oder Daten außerhalb ihrer selbst preisgeben, die eine Sicherheitslücke verursachen können, aber für Tests nützlich sind.“
Eine solche App habe ich bislang noch nicht gesichtet – aber „Vorsicht ist die Mutter der Porzellankiste“, oder so. Besser keine Elefanten reinlassen.android:usesCleartextTraffic
: Internet-Traffic sollte verschlüsselt sein. Im Web-Browser bedeutet dies:https://
. Istandroid:usesCleartextTraffic
aktiviert heißt dies, die App möchte auch unverschlüsselte Verbindungen nutzen. Hier gilt es genau nachzuschauen, wofür. Für Zugriffe innerhalb des Heimnetzes (etwa auf den selbst gehosteten Medienserver) ist es völlig OK – hier wäre es ja auch schwierig, ein valides Zertifikat erstellt zu bekommen, da dieser Server in der Regel ja von außen nicht erreichbar ist (und auch nicht sein soll). Werden allerdings (sensible) Daten unverschlüsselt ins „offene Netz“ übertragen, ist das mehr als nur fahrlässig – da es u. a. die Gefahr von MITM und das damit verbundene Abgreifen Eurer Daten durch unbefugte deutlich erhöht. „Der Hauptgrund für die Vermeidung von Klartextverkehr ist der Mangel an Vertraulichkeit, Authentizität und Schutz vor Manipulationen. Ein Angreifer im Netz kann die übertragenen Daten abhören und auch verändern, ohne entdeckt zu werden.“
Heikle Berechtigungen
Diese lösen eine Warnung aus, welche eine manuelle Prüfung nach sich zieht. Passen sie zum Einsatzzweck der App und sind für die angepriesene Funktionalität notwending, kommen sie in die „Allow-List“ der App – etwa CONTACTS
für eine Adressbuch-App oder CALL_PHONE
für einen Dialer. Andere werden im Abschnitt „Berechtigungen“ der entsprechenden APK hervorgehoben - oder können zur Entfernung (bzw. Nichtaufnahme) der App führen. Eine Liste dieser „heiklen“/sensiblen Berechtigungen findet sich in Issue 475 sowie in der entsprechenden Library-Datei. Diese Berechtigungen betreffen sowohl Sicherheitsthemen als auch Fragen des Datenschutzes.
Eine spezielle Berechtigung in diesem Kontext ist REQUEST_INSTALL_PACKAGES
, welche üblicherweise auf einen integrierten Selbst-Updater hindeutet – und somit auf eine Verletzung der Aufnahme-Kriterien des Repos, da ein solcher die bestehenden Sicherheitskontrollen umgehen würde. Daher wende ich mich in einem solchen Fall an die jeweiligen Entwicker, um dies zu prüfen (die Berechtigung könnte durchaus anders begründet sein; z. B. könnte ein Dateimanager sie für die Installation lokal gespeicherter APK Dateien brauchen). Sollte es sich tatsächlich um einen Selbst-Updater handeln, bitte ich um ein separates Build-Flavor ohne diesen Selbst-Updater, oder zumindest um die Implementierung eines Opt-In mit entsprechenden Hintergrund-Informationen, wie es die Beispiel-Screenshots der App RiMusic unter diesem Absatz zeigen. Ausnahmen davon gibt es nur sehr selten – etwa für dedizierte Test-Versionen von Apps, etwa „beta channels“, die dann aber auch klar als solche erkennbar sein müssen. Bislang stießen meine diesbezüglichen Anfragen weitgehend auf Verständnis.


(ein Klick auf die Screenshots vergrößert diese)
Sensible Berechtigungen werden manuell überprüft, bevor eine neue App zum Repo hinzugefügt wird, aber auch automatisch bei jeder eingehenden Aktualisierung. Gerechtfertigte werden der „Allow-List“ der App hinzugefügt (und wieder von selbiger entfernt, sollten sie aus der App wieder entfernt worden sein). Bei Unklarheiten wende ich mich an die jeweiligen Entwickler, die diese dann i. d. R. klären oder aber auch entfernen bzw. ersetzen (ein Prozess, der bisher sehr gut funktioniert hat). Die übrigen sind, wie bereits erwähnt, deutlich gekennzeichnet oder können in schwerwiegenden Fällen zur Entfernung der App aus dem Repo führen.
Sensible Intent-Filter
Bei Android-Apps ist ein „Intent“ die abstrakte Beschreibung einer auszuführenden Operation. Grundlegend gibt es dabei drei Hauptanwendungsfälle: Das Starten einer Aktivität, eines Service, und um Nachrichten an einen BroadcastReceiver zu übermitteln, den andere Anwendungen abonnieren können, um diese Nachrichten zu empfangen.

Einige dieser Intent-Filter lösen bei den Scans analog zu den „heiklen Berechtigungen“ Warnungen aus, da sie auf unerwünschtes Verhalten hinweisen könnten – und werden dann genau so behandelt: manuelle Prüfung, Anfrage bei den Entwicklern sofern nötig. Anschließend wiederum: Aufnahme in die „Allow-Liste“, auslösen eines Anti-Features – oder Ausschluss (Entfernung) der App aus dem Repo.
android.accessibilityservice.AccessibilityService
: Hier möchte eine App sich Android’s AccessibilityService zunutze machen. Das ist jetzt nicht unbedingt etwas schlechtes oder gefährliches, bietet aber deutliches Missbrauchspotential. Einige Aktionen werden bewusst implementiert um sicherzustellen, dass sie von dem Menschen, der das Gerät bedient, direkt ausgeführt werden und nicht von einer App hinter seinem Rücken. AccessibilityServices bieten die Möglichkeit, dies zu automatisieren (um „Benutzer mit Behinderungen bei der Nutzung von Android-Geräten und -Apps zu unterstützen“), so dass sichergestellt werden sollte, dass eine App sie auf verantwortungsvolle Weise nutzt.android.net.VpnService
: Wie der Name es bereits vermuten lässt, möchte diese App Android‘s VpnService nutzen – was auch das Abfangen des Netzwerk-Traffics ermöglicht. Dies sollte ausschließlich VPN-Apps vorbehalten sein – mit Ausnahmen für Apps wie Netguard, Tracker Control und ähnlichen nicht-root-voraussetzenden Werbeblockern und Firewalls.android.view.InputMethod
Eine Input-Methode (IME; Eingabemethode) ist etwas, mit dem (unter Nutzung von Android’s InputMethod framework Benutzereingaben erfasst werden – am bekanntesten sicher Tastatur-Apps wie AnySoftKeyboard oder HeliBoard, aber auch QR-Code Scanner zur Inventarisierung können dies nutzen. Und nur solchen Apps sollte dies auch vorbehalten sein.
Intent-Filters werden bei der Aufnahme von Apps manuell, aber auch automatisch durch den Update-Checker für jede eingehende APK-Datei geprüft.
Wenn ein solcher von einer App verwendet wird, muss dies transparent gemacht werden. Diese Überarbeitung beinhaltet also genau das: die Gründe dafür sichtbar zu machen (in einem separaten Block auf der App Details Seite der Website des Repos mit der Bezeichnung „Anwendungskonfiguration & Spezielle Zugriffsmethoden“, zusammen mit den oben erwähnten „Flags“).
Zertifikate und Signierung
Zertifikate kommen zum Einsatz, um Apps zu signieren. Sie werden üblicherweise von den Entwicklern selbst erstellt und ihn ihren privaten Keystores gespeichert – zumindest sollte das für die über das IzzyOnDroid Repository bereitgestellten APK-Dateien gelten. Ausnahmen davon finden sich etwa in Google’s PlayStore, wo Google das Signieren lieber selbst übernehmen möchte – sowie bei F-Droid‘s eigenem Repository, für das F-Droid die entsprechenden Zertifikate in den Fällen selbst generiert, in denen keine reproducible builds etabliert werden konnten.
App Signing ist ein Security Feature. Damit soll sichergestellt werden, dass die APK nicht manipuliert werden kann (so dass niemand z. B. bösartige Elemente einfügen kann) und dass sich unabhängig überprüfen lässt, ob die APK wirklich von dem entsprechenden Entwickler bereitgestellt wurde. Updates für eine installierte App werden nur akzeptiert, wenn die Signatur der entsprechenden APK-Datei mit der der bereits installierten App übereinstimmt. Was nur der Fall ist, wenn beide mit demselben Zertifikat signiert wurden. Die Zertifikate einer APK-Datei lassen sich zum Beispiel mit einem Tool namens apksigner
überprüfen:
$ apksigner verify --verbose --print-certs org.fdroid.fdroid.apk
Verifies
Verified using v1 scheme (JAR signing): true
Verified using v2 scheme (APK Signature Scheme v2): true
Verified using v3 scheme (APK Signature Scheme v3): true
Number of signers: 1
Signer #1 certificate DN: CN=Ciaran Gultnieks, OU=Unknown, O=Unknown, L=Wetherby, ST=Unknown, C=UK
Signer #1 certificate SHA-256 digest: 43238d512c1e5eb2d6569f4a3afbf5523418b82e0a3ed1552770abb9a9c9ccab
Signer #1 certificate SHA-1 digest: 05f2e65928088981b317fc9a6dbfe04b0fa13b4e
Signer #1 certificate MD5 digest: 17c55c628056e193e95644e989792786
Signer #1 key algorithm: RSA
Signer #1 key size (bits): 2048
Signer #1 public key SHA-256 digest: e3d2cc87a245da2e84d4fb71e527c164e084d48bccf76ffad46ad17f1bfde388
Signer #1 public key SHA-1 digest: 26ef7882633282a9b04688178ee7f372fbec7c3d
Signer #1 public key MD5 digest: 9225fccafb33b605a86cfc09d7f38ec6
Wenn eine App zum IzzyOnDroid Repository hinzugefügt wird, wird das zum Signieren verwendete Zertifikat gepinnt: AllowedSigningKeys
wird auf den Wert von Signer #1 certificate SHA-256 digest
gesetzt. Updates für diese App werden dann nur akzeptiert, wenn die Zertifikate übereinstimmen. Damit soll verhindert werden dass eine APK, die möglicherweise manipuliert wurde, überhaupt in das Repository gelangt. Während eine solche APK für diejenigen, die die Vorgängerversion auf ihrem Gerät haben, nicht installiert (oder auch nur als Update angeboten) werden würde, schützt das Verhindern der Aufnahme in das Repository diejenigen, die die App zum ersten Mal installieren würden.
Aber das ist nicht das einzige, was auf dieser Ebene geprüft wird. Schauen wir uns an, was sonst noch geschieht:
Debug-Zertifikate & schwache Zertifikate
Diese werden lediglich bei der Aufnahme neuer Apps geprüft – Apps, die mit Debug-Zertifikaten signiert wurden, werden nicht mehr ins Repository aufgenommen. Da Zertifikate, wie beschrieben, bei der Aufnahme ins Repository per AllowedSigningKeys
gepinnt werden, können solche APKs auch nicht mit Updates hinein gelangen: APKs mit einer abweichenden Signatur (das Verwenden eines anderen Zertifikats führt definitiv zu einer solchen) würden somit automatisch abgewiesen und nicht einmal in den Index gelangen können. Es wurde ein Scan über alle APKs durchgeführt, die sich derzeit im Repo befinden, um diejenigen zu finden, die ein Debug-Zertifikat verwenden (siehe scan existing APKs for use of debug keys) und zeigte, dass es zunächst 112 solcher APKs gab, 40 von ihnen sogar mit abgelaufenen Debug-Schlüsseln (das bedeutet nicht 112 bzw. 40 Apps, da es bis zu 3 APKs pro App im Repo geben kann). Mit den letzteren 40 wurde begonnen: 23 Apps, die offensichtlich nicht mehr gepflegt werden (Repositories gelöscht/archiviert, Autor seit Jahren nicht mehr gesehen usw.), wurden entfernt, für die übrigen habe ich die Autoren kontaktiert. Einige davon wurden innerhalb einer Woche korrigiert, andere wurden überhaupt nicht beantwortet. Letztere wurden ebenfalls entfernt, wenn innerhalb eines Monats keine Antwort einging (oder wenn die Autoren erklärten, sich nicht darum kümmern zu wollen).
Die restlichen 72 wurden in einem separaten Durchlauf behandelt. Die meisten davon sind bereits geklärt: In der Regel haben die Entwickler zu einem richtigen Release-Schlüssel gewechselt, und die Debug-Versionen wurden hier entfernt. Die letzten mit einem Debug-Schlüssel signierten APKs sollten Ende März 2024 verschwunden sein.
Diejenigen, die sich fragen warum dies ein Problem sein sollte, finden Antworten unter anderem hier:
Außerdem weist ein richtiges Release-Zertifikat in seiner DN darauf hin, wer das Zertifikat erstellt hat – während bei Debug-Schlüsseln immer steht, dass es "Android Debug" war:
Signer #1 certificate DN: C=US, O=Android, CN=Android Debug
Für diejenigen, die sich für die technischen Details interessieren, sind dies die Befehle, mit denen sie aufgespürt wurden:
apksigner verify --verbose --print-certs $apk |grep "Android Debug"
jarsigner -verify -verbose -certs $apk |grep deny |sed "s/.*denyAfter \(.*\),.*/\1/"
(die ältesten zuerst; was abgelaufen ist und nicht mehr gewartet wird, wird entfernt; funktioniert nur bei Apps mit einer v1-Signatur, schlägt bei solchen mit nur v2/v3 fehl; es wurden nur die APKs überprüft, die beim ersten Durchlauf erkannt wurden und alle eine v1-Signatur hatten)
Tipp für Entwickler: Da die Verwendung eines anderen Signierschlüssels bedeutet dass alle, die die App bereits verwenden, die alte Version deinstallieren müssen, bevor sie die neue installieren können, sollte „Schlüsselrotation“ in Betracht gezogen werden. Die Schlüsselrotation kann mit apksigner
durchgeführt werden, wenn man sowohl Zugang zum ursprünglichen als auch zum neuen privaten Schlüssel hat. Ich habe noch nicht getestet, ob fdroidserver dies unterstützt; wer möchte kann sich aber gerne an mich wenden, damit ich einen Test durchführen kann. Da die Schlüsselrotation erst mit Android 9 eingeführt wurde, ist dies nur möglich, wenn die minSdkVer
der App Android 9 oder höher entspricht.
BLOBs in APK Signing Blöcken
In den so genannten „Signing Blocks“ findet sich ggf. deutlich mehr als nur etwa Signatur-Informationen. Und so wies mich Fay darauf hin, dass es hier mitunter recht merkwürdig zugehen kann. Es finden sich hier natürlich Dinge, die hier auch hingehören und die man hier vermuten würde:
OK_BLOCKS = dict(
# https://source.android.com/docs/security/features/apksigning/v2#apk-signing-block-format
APK_SIGNATURE_SCHEME_V2_BLOCK=0x7109871a,
APK_SIGNATURE_SCHEME_V3_BLOCK=0xf05368c0,
APK_SIGNATURE_SCHEME_V31_BLOCK=0x1b93ad61,
VERITY_PADDING_BLOCK=0x42726577,
)
Daneben aber leider auch noch einiges andere, was für Open-Source Apps eher nicht zuträglich ist:
DEPENDENCY_INFO_BLOCK
: Dies soll eine binäre Darstellung der build dependencies sein – also was bei der App zur Erstellung zum Einsatz kam. Dummerweise ist es mit einem public key verschlüsselt, der Google gehört1 – sodass nur Google selbst dies lesen und mit Sicherheit sagen kann, was dort wirklich drin ist. Für alle anderen ist dies ein opaker „BLOB“ (Binary Large OBject). Eingefügt wird dieser beim Signieren der App – also entweder von Google selbst nach dem Hochladen in den PlayStore, oder aber von Software wie Android Studio oder IntelliJ IDEA. Entwickler haben zum Glück relativ einfache Möglichkeiten, dies zu vermeiden – welche ich ihnen beim Auffinden dieses BLOBs auch jeweils nahelege.GOOGLE_PLAY_FROSTING_BLOCK
: Wem es beim Namen fröstelt: Ja, dieser BLOB ist nur für den PlayStore interessant. In der Open-Source-Welt haben wir dafür keine Verwendung. Trifft man diesen also an weiß man: Die APK stammt aus dem PlayStore. Ein Post bei StackOverflow gibt ein wenig Hintergrund dazu, das Wesentliche übersetzt: „Der Frosting-Block wird vom Play Store hinzugefügt, was beweist, dass eine bestimmte Datei aus dem Play Store heruntergeladen wurde […] Seltsamerweise enthält das Frosting einen Metadaten-Chunk, der mit protbuf kodiert ist. Die Struktur ist ziemlich komplex ...“
Ich bin noch nicht auf eine APK gestoßen, die diesen Block enthielt – wie damit umzugehen wäre, muss sich also erst noch zeigen. Wenn immer möglich, sollte die Lösung lauten: „Lieber Entwickler, bitte signiere die APK selbst und achte darauf, auch denDEPENDENCY_INFO_BLOCK
zu vermeiden“ – der in diesem Fall wahrscheinlich auch vorhanden wäre.- Zu
SOURCE_STAMP_V1_BLOCK
undSOURCE_STAMP_V2_BLOCK
finden sich Informationen in den Kommentaren der Quellcode-Datei SourceStampVerifier.java. Ich übersetze den wesentlichen Teil mal schnell mit DeepL: „SourceStamp verbessert die Rückverfolgbarkeit von Apps im Hinblick auf eine nicht autorisierte Verbreitung. Der Stempel ist Teil der APK, die durch den Signierblock geschützt ist. Der Hash des APK-Inhalts wird mit dem Stempelschlüssel signiert und als Teil des Signierblocks gespeichert.“
In der Open-Source-Welt stehen die Apps unter freien (libre) Lizenzen, und die Four Essential Freedoms of Free Software sind garantiert. Diese beinhalten u. a. „The freedom to redistribute copies so you can help your neighbor“ (freedom-2) und „The freedom to distribute copies of your modified versions to others“ (freedom-3). So etwas wie „nicht autorisierte Verbreitung“ kann es da also nicht geben, womit für diese Blöcke auch kein Bedarf besteht.
Ein kurzer Blick auf den Code (bitte dabei bedenken, dass ich kein Java-Entwickler bin) scheint zu zeigen dass damit sichergestellt werden soll, dass alle geteilten APKs aus der gleichen Quelle stammen. Der Code zur Überprüfung ist öffentlich/FOSS, so dass ich nicht sehe, warum dies Anlass zu Bedenken geben sollte – außer, dass es von einer dritten Partei eingefügt wurde, bei der es sich höchstwahrscheinlich um Google handelt. Und Google schreibt dazu, kurz übersetzt: „Für Apps, die als App-Bundles hochgeladen werden, verbessern wir diese Sicherheit durch die Einführung eines sogenannten Quellstempels. Diese Quell-Metadaten werden von bundletool in das Manifest der App eingefügt. Wenn die APK auf dem Play-Server generiert wird, wird sie zusätzlich zu Ihrem App-Signierschlüssel auch mit einem Google-Schlüssel signiert.“ Dabundletool
verwendet werden kann, um dies einzufügen, könnten allerdings auch die ursprüngliche Entwickler diesen Block eingefügt haben.
Auch auf diese Blöcke bin ich noch nicht gestoßen und benötige mehr Informationen, um zu entscheiden, wie mit ihnen umzugehen wäre. Aber zumindest wird automatisch darauf geprüft und bei Antreffen eine Warnung generiert – wie auch für die anderen.
Bis hierhin schaut es noch fast ein wenig harmlos aus. Bei meinen Recherchen stieß ich aber noch auf einen weiteren Block:
MEITUAN_APK_CHANNEL
: Hier hat die chinesische Firma Meituan einen Weg gefunden, Payload in den Signing Blöcken unterzubringen. Einen Beleg für diesen Block findet Ihr hier – und einen Beleg dafür, dass er für Payload (in diesem Fall in Form von JSON) verwendet wird, hier. Payload in einem Signing Block darf durchaus als Sicherheitsrisiko angesehen werden, weshalb man hier wachsam sein sollte.
Es könnte auch andere Blocktypen geben, denn Entwickler könnten einfach ihre eigenen Blocktypen erstellen (oder vorhandene missbrauchen) und alles darin unterbringen, was sie möchten, einschließlich Code. Weshalb auch „unbekannte Blöcke“ eine Warnung auslösen – einschließlich der an mich gesendeten Mail. Wie schon bei den Prüfungen auf heikle Berechtigungen und sensiblen Intent-Filtern erfolgt diese Prüfung sowohl manuell bei Aufnahme neuer Apps, als auch automatisch bei jedem Update. Wer selbst APKs prüfen möchte, findet das passende Skript hier. In selbigem finden sich auch alle derzeit bekannten Blöcke aufgeführt, einschließlich Links zu Details über sie.
Wie beim DEPENDENCY_INFO_BLOCK
ausgeführt, empfehle ich die Verwendung von apksigner
für das Signieren, um einige dieser BLOBs von vornherein zu vermeiden. Gemäß der offiziellen Dokumentation lassen sich Android Studio und auch IntelliJ IDEA vom Einfügen dieses Blocks auch abhalten, wenn man folgendes Snippet in die build.gradle.kts
einbindet:
android {
dependenciesInfo {
// Disable including dependency metadata when building APKs
includeInApk = false
// Disable including dependency metadata when building Android App Bundles
includeInBundle = false
}
}
Danke an Naveen für den Hinweis, und an soupslurpr für den Hinweis, auch AABs so zu behandeln! Mittlerweile hat sich der Ansatz, den DEPENDENCY_INFO_BLOCK
über die skizzierte Modifikation der build.gradle
auszuschließen, als erfolgreich erwiesen und wurde im Quellcode mehrerer Apps aus dem IzzyOnDroid-Repository angewendet.
Derzeit werden SigningBlock-BLOBs nur in der APK-Checker-Datenbank des Repositorys erfasst und auf der Website sichtbar gemacht. Wie dies in Zukunft gehandhabt werden soll, wird in einem separaten Thema verfolgt: Dealing with BLOBs found in APK signing blocks.
Noch ein Wort dazu: Wie das Beispiel des Payload von Meituan zeigt, ist dies nicht nur eine „kosmetische Angelegenheit“. Man kann eine APK nehmen, die ordnungsgemäß mit dem Schlüssel des Entwicklers signiert ist, etwas zum Signierblock hinzufügen – und die Verifizierung mit apksigner
gelingt trotzdem vollständig, als ob nichts falsch wäre. Die modifizierte App lässt sich sogar auf einem Android-Gerät ordnungsgemäß installieren – das ist also durchaus ernst zu nehmen. Details dazu finden sich u. a. in diesem POC. Ein kurzes Zitat aus dem POC, frei übersetzt:
Ob der Payload vorhanden ist oder nicht, hat keinen Einfluss auf die Gültigkeit der Signatur. So erhalten wir zwei APKs – mit einer identischen gültigen v1+v2+v3-Signatur – aber eine sagt "Hier gibt es nichts zu sehen...", wenn man sie ausführt, während die andere z.B. sagt "Dies ist der Payload".
In einem Test wurde das EICAR sample auf diese Weise in eine APK-Datei eingeschleust und zu VirusTotal hochgeladen. Nur 2 der 64 Scanner dort erkannten es – was bedeutet, dass eine derartige Manipulation in vielen Fällen unerkannt bliebe. Doch selbst wenn deutlich mehr Malware-Scanner es entdecken würden wäre dies ein schlechtes Zeichen, solange die Signaturprüfung es nicht bemerkt: ein böswilliger Akteur könnte die APK eines seriösen Autors nehmen, einem Signierungsblock Malware hinzufügen und die daraus resultierende APK verbreiten, wodurch der Ruf des ursprünglichen Autors geschädigt würde – der dafür verantwortlich gehalten wird, da die Signatur „beweist“ das er es war.
In einem weiteren Test wurde ein ELF binary auf diese Weise in einen Signing Block eingebracht. VirusTotal schien das überhaupt nicht zu sehen. Pithus hat in diesen Fällen zumindest auf die „unbekannten“ Blöcke hingewiesen.
Warum ist dies nun ein Sicherheitsproblem? Android Apps haben Zugriff auf ihre eigenen APK-Datei, und können somit auf diese Weise Payload hier verstecken (und einige tun dies bereits, wie das Beispiel des MEITUAN_APK_CHANNEL
zeigt). Da die meisten Scanner die Signierblöcke vollständig ignorieren, stellt dies ein Risiko dar, das behoben werden sollte.
Danke an Fay für die Bemühungen, die sie in diese Sache gesteckt hat!
Reaktionen von kontaktierten Entwicklern
Bislang wurden alle meine Berichte, sofern sie beantwortet wurden, gut aufgenommen und Anregungen entsprechend umgesetzt. Entweder sind die „potentiellen Übeltäter“ geklärt worden (mit Links zum Quellcode und entsprechenden Erklärungen) – oder meine Berichte führten zu Verbesserungen der App selbst, da selbige „Übeltäter“ entfernt wurden (teilweise mit Codeumstellungen unter Verwendung weniger „anstößiger“ Implementierungen), oder indem begründete Fälle transparenter gemacht und den Nutzern der App erklärt wurde, wenn die entsprechende Funktion ausgelöst wurde (z. B. indem bei android:usesCleartextTraffic
bei Eingabe einer unsicheren URL gefragt wird, ob dies wirklich beabsichtigt war oder nur ein Tippfehler (das s
in https
vergessen?) vorliegt – manchmal auch beides, wie im beschriebenen Beispiel.
Fazit
Security ist kein „Set-and-Forget“, sondern ein fortlaufender Prozess. Dies ist nun die dritte „große Runde“ von Prüfungen, die im IzzyOnDroid Repository implementiert wurden – und wird definitiv nicht die letzte sein. Wie gezeigt, ist die Transparenz ein wichtiger Aspekt dieses Repositorys, um Euch zu zeigen „was drin ist“ selbst wenn es kein Sicherheitsproblem ist – damit Ihr, sollte etwas verdächtig aussehen, hoffentlich zumindest eine Erklärung dafür findet, warum es da ist.
„Dinge sicher(er) zu machen“ ist auch ein Lernprozess. Ich bin dankbar für alle Hilfe, die ich von Entwicklern erhalten habe, die mir (der kein Android-Entwickler ist) die Hintergründe und Einsatzzwecke erklärt haben. Und ich bin froh dass ich einigen Entwicklern mit dem, was ich auf diesem Weg gelernt habe, helfen konnte. Diese Zusammenarbeit empfinde ich als sehr wichtig, da es uns allen hilft, uns zu verbessern – und unsere Androiden zu sichereren Orten zu machen. Lasst uns das beibehalten!
-
Apkverifier enthält einen kurzen Kommentar im Quellcode, u. a. „The data is compressed, encrypted by a Google Play signing key...“ ↩︎