App Security, die Zweite

Sorry, this entry is only available in German. For the sake of viewer convenience, the content is shown below in the alternative language. You may click the link to switch the active language.

Nachdem App Security immer wichtiger wird, und mein letzter Blog darüber schon eine Weile her ist, möchte ich diesen hier fortsetzen. Diverse Grundlagen, dass man z.B. immer SSL zur Kommunikation verwendet, sollten ja jedem Entwickler bekannt sein. Um aber die App besser abzusichern, müssen wir auch auf die “andere Seite” schauen, also den Blickwinkel eines Angreifers beachten. Dies wird hier am Beispiel “lokale Datenspeicherung” beschrieben.

App Security titelbild Blogbeitrag

Um dem Artikel gut folgen zu können, sollte man zumindest Programmierkenntnisse haben. Android oder iOS Kenntnisse sind nicht unbedingt notwendig, aber schon hilfreich 😉

App Security: Welche Daten darf eine App am Smartphone wie hinterlegen?

Meist werden in Apps diverse Daten permanent (bzw. zumindest, bis man die App wieder deinstalliert) abgespeichert. Seien es Einstellungen, die der User darin vornimmt, oder Daten, die von einem Server geliefert werden. Problematisch wird es, wenn sensible Daten, wie Passwörter, API-Keys, usw. gespeichert werden sollen. Zunächst müssen wir uns mal anschauen, welche Möglichkeiten es gibt, Daten in Apps permanent zu speichern. Danach können wir uns Szenarien ausmalen, wie ein Angreifer diese Daten auslesen oder verändern kann, und was man andererseits dagegen unternehmen kann.

Sowohl Android als auch iOS bieten zum einen die Möglichkeit, Daten in Key-Value Paaren zu speichern. Unter Android sind das die sogenannten SharedPreferences, unter iOS die UserDefaults. Andererseits gibts auch API’s zum Speichern von Dateien im internen Dateisystem. Diese Dateien sollen dann nur für die jeweilige App sichtbar sein. Unter Android kann man Daten auch in den externen Speicher legen. Auf diesen kann man ganz einfach zugreifen.

Man braucht nicht weiter zu erwähnen, dass sensible Daten nie im externen Speicher abgelegt werden dürfen. Aber wie sieht es mit den anderen Möglichkeiten aus für eine 100 %ige App Security?

Angenommen ich will in einer App eine PDF Datei aus dem Backend anzeigen, will aber möglichst vermeiden, dass dies ausgelesen wird (manche Leute wollen ja alles im Internet verbreiten). Die App lädt also das PDF (natürlich über SSL, siehe alter Blogeintrag) runter, und speichert die Datei im internen Speicher. Solange der User nicht böswillig ist, stellt dies auch kein Problem dar.

gerooteten Android bzw. iPhone mit Jailbreak

Ein Angreifer würde die App beispielsweise auf einem gerooteten Android, bzw. einem iPhone mit Jailbreak installieren. Damit kann man dann auch auf den App-internen Speicher zugreifen. Schon ist das PDF einfach vom Smartphone runterkopiert. Zumindest bei älteren (wahrscheinlich aber auch bei neuen) iOS Versionen ist ein Jailbreak nicht einmal notwendig. Tools wie iFunbox erlauben auch so den Zugriff auf den Speicher. Eine erste Verbesserung wäre es, die Datei im internen Speicher zu verschlüsseln. Hier nimmt man am besten einen schnellen symmetrischen Verschlüsselungsalgorithmus, wie AES. Solche Algorithmen gelten als sehr sicher. Man kann die Datei also nur mit Wissen des Schlüssels wieder entschlüsseln. Und darin erahnt man schon das Problem: wie hinterlege ich dann den Schlüssel sicher?

Wenn man den Schlüssel auch vom Server bekommt, wäre der erste Gedanke, diesen in den SharedPreferences, bzw. auf iOS in den UserDefaults abzulegen. Es stellt sich jedoch heraus, dass diese Daten auf gerooteten Android Geräten auch einfach ausgelesen werden können. Am iPhone werden diese genau am App-internen Speicher, den wir ja zuvor schon ausgelesen haben in einem .plist File abgespeichert. Dies ist nichts weiter als eine XML Datei, und daher leicht zu lesen und auch abzuändern.

Kurzum, wenn der User sich schon die Mühe gemacht hat, die Datei vom internen Speicher zu holen, ist es kein großer Schritt, einen auf diese Weise hinterlegten Schlüssel zu holen. Jedoch weiß der Angreifer damit noch nicht, welchen Algorithmus man verwendet, usw. Diese vermeintliche “Sicherheit” wird auch Security through Obscurity genannt. Unser Angreifer kommt entweder durch probieren, oder raffiniertere Strategien (siehe weiter unten) dahinter. Man kann es ihm dadurch schon erschweren, an die Daten zu kommen.

Eine weitere Möglichkeit wäre, einen fixen Schlüssel zu verwenden, der im Programmcode enthalten ist. Um den herauszufinden müsste der Angreifer ja schon den Source Code haben, oder?

Dekompilieren und Konsorten…

Den Source Code aus einer installierten Android App zu extrahieren ist meist kein großer Aufwand. Dazu muss das Smartphone nicht einmal gerootet sein. Ein kurzer Blick auf Stack Overflow, und schon hat man das apk Package. Dieses enthält den kompilierten Source im dex (Dalvik Executable) Format. Mit Tools wie dex2jar ist es ein Leichtes, Java .class Dateien daraus zu erzeugen. Für diesen Java Bytecode gibt es wiederum Decompiler, die daraus wieder den .java Source Code extrahieren. Sogar die Variablennamen sind in den .class Dateien kodiert. Abhilfe schaffen hier Code Obfuscater (ProGuard bzw. R8 unter Android). Ein Verschlüsselungskey wäre aber vermutlich trotzdem Schnell gefunden.

Java Bytecode, wie er von Java, Kotlin und Konsorten erzeugt wird, ist hier besonders betroffen. Aber auch aus .dll Dateien, die von Unity erzeugt, und in Apps gepackt werden, sind mit verschiedensten Tools wieder in C# Code umwandelbar.

Etwas mehr (bzw. anderes) Domänenwissen wird dem Angreifer abverlangt, wenn man sensible Codeteile nativ, also unter Android per NDK einbindet. Im .apk Package ist dieser Code dann als Shared Library (.so Datei) enthalten. Swift- und ObjC-Code unter iOS sind ebenfalls nativ kompiliert. Diese Binärdatei kann man nicht mehr in eine höhere Programmiersprache zurücksetzen. Allerdings gibt es auch für diese Assemblies gute Analysetools. Hier sieht man einen Screenshot von Radare, einem OpenSource Reverse Engineering Tool:

App Security

Die hier analysierte Software ist übrigens ein Teil der ls Implementierung der GNU CoreUtils (damit man hier nicht denkt, ich würde illegal Software reverse engineeren). Wie man sieht, braucht man hier schon Assembler-Basiswissen. Meist weiß man als Angreifer aber, wonach man suchen muss, und die Tools unterstützen einen da sehr. Es gibt übrigens neben Radare auch andere Tools mit schönerer UI, wie zum Beispiel das von der NSA veröffentlichte GHIDRA, oder (wenn man das nötige Kleingeld für die Lizenz ausgeben will) die reverse engineering Software IDA Pro.

Mit diesen Tools kann man sogar den Code Patchen (wenn man z.B. eine if-Abfrage umgehen will), oder auch (im Fall von Radare und IDA Pro) debuggen. Wenn ich mich hier gut auskenne, kann ich mit solchen Techniken jedenfalls auch die im letzten Blog beschriebene SSL Verbindungssicherheit aushebeln.

2. Schlussfolgerung von App Security

100%ige App Security hat man bei Apps leider nie. Auf Android ist ein App, aufgrund der schon prinzipiell offeneren Systemarchitektur, tendenziell leichter anzugreifen, als auf iOS. Auf eine gewisse Grundsicherheit muss man in der Entwicklung immer achten. Der Aufwand steigt bei der Absicherung gegen weitere Angriffe schnell sehr stark an – fast immer schneller als der Aufwand, die Absicherung auszuhebeln. Schließlich schaffen es oft nicht mal die größten Softwareunternehmen mit großem Budget, wie Microsoft oder Apple, ihre Software vor erfolgreichen Angriffen zu schützen.

Grundsätzlich ist der beste Ansatz, die notwendige Absicherung immer pro App individuell zu gestalten. Hier sind Fragen wie “welche Daten muss ich wirklich der App zur Verfügung stellen”, oder “wem ist die App zugänglich” relevant. Falls eine App Beispielsweise ohnehin nur das Personal eines Businesskunden verwenden kann, fällt das Szenario des Hackers, der sich die App samt Daten holt und analysiert meist weg.

Für diejenigen, die sich für weitere, spezielle Absicherungstechniken für Android und iOS interessieren, sei hier noch The Mobile Security Testing Guide empfohlen.