Android-Apps können, wie Web-Applikationen oder native Desktop-Applikationen auch, Schwachstellen enthalten und die Sicherheit ihrer Benutzer oder sogar der dahinterliegenden Server beeinträchtigen.
Bei unseren Penetration Tests von Mobilen Apps sehen wir immer wieder fundamentale Fehler, die während der Entwicklung einfach vermieden werden können.
Dieser Artikel sollte keinesfalls als Ersatz für die offiziellen Sicherheitsrichtlinien von Google oder Apple verstanden werden. Diese Dokumente sind essentiell für die sichere Entwicklung und am Ende des Blogs finden Sie die wichtigsten Links. Wir wollen lediglich eine kurze Übersicht von häufigen Problemen aufzeigen, denen wir immer wieder begegnen.
Grundsätzlich kann man sich an klassische Prinzipien der sicheren Programmierung halten. Dabei kann man sich das Prinzip der geringsten Rechte (engl. „Principle of least privilege“) und das DOTADIW-Konzept (engl. „Do One Thing and Do It Well.“, also mache eine Sache und mache die gut) vor Augen halten.
Weniger ist mehr aus der Sicht der Sicherheit. Je weniger Funktionen eine Applikation übernimmt, desto weniger Angriffsfläche gibt es und umso weniger mögliche Schwachstellen gibt es. Leider erscheint das aus der Benutzerperspektive vielleicht nicht so sinnvoll. Hierbei muss man das klassische Dilemma Benutzerfreundlichkeit gegen Sicherheit von Fall zu Fall betrachten und abwiegen, was mehr Gewichtung hat.
Ein weiterer universaler Grundsatz ist es, Benutzerdaten niemals zu vertrauen. Jegliche Benutzerdaten müssen als potentiell bösartig angesehen werden. Aus diesem Grund sollten alle Daten, die vom Benutzer direkt oder indirekt generiert werden, verifiziert und bereinigt werden. Zu diesem Thema folgt zukünftig ein eigener Blogartikel. Nach dem alten Sprichwort „Doppelt hält besser“ lieber zwei Mal Daten prüfen als eine Schwachstelle in der Applikation zu haben, also in der Applikation bei der Eingabe und nach dem Versenden auf dem Server. In Verbindung mit Datenbanken werden hier „Prepared Statements“ (oder „Parameterized Statement“) empfohlen, um potentiellen SQL-Injections durch schädliche Benutzerdaten zu verhindern.
Verschlüsselung ist ein heikles, aber essentielles Thema. In diesem Blogartikel haben wir das Thema behandelt. Allgemein sollte man sich hier an den aktuellen Stand der Technik halten und keine Eigenentwicklungen verwenden, sondern sich auf empfohlene Bibliotheken verlassen. Das sichere Speichern von Daten auf Android wird in der Dokumentation behandelt (siehe wichtige Links).
Für die Kommunikation ist nach wie vor TLS die Standardmethode, um Daten zu verschlüsseln. Die TLS-Konfiguration sollte den Umständen angepasst sein und Serverzertifikate müssen überprüft werden.
Genau wie für andere Technologien kann man davon ausgehen, dass clientseitige Überprüfungen sicherheitstechnisch irrelevant sind, diese dienen lediglich der Benutzererfahrung. Wenn also beispielsweise ein Eingabefeld nur bestimmte Zeichen enthalten darf, dann dient die Überprüfung auf Korrektheit in der App (also clientseitig) nur der Benutzererfahrung. Die Daten müssen auf dem Server erneut verifiziert werden.
Im Normalfall ist eine Mobile App nicht alleinstehend, es gibt meist einen dazugehörigen Webservice. Häufig spricht man hier von APIs, die der App erlauben, mit einem Server zu sprechen. Es ist dabei zu beachten, dass auch die sicherste App wenig bringt, wenn die Kommunikation zu dem Webservice Schwachstellen aufweist. Wenn also die dahinterstehende REST API das Rollen- und Rechtesystem nicht vernünftig implementiert, ist der Dienst auch trotz sicherer mobiler App unsicher.
Activities, Intents, Services, Broadcasts, …
Android-spezifischer wollen wir hier klassische Themen aufzeigen, die wir bei unseren Audits häufig finden und zu Schwachstellen führen können.
Eine Activity ist in Android eine Aktion, die ein Benutzer durchführen kann. Eine typische Activity, die eine Android App mit grafischer Oberfläche hat, ist die Main Activity, die beim Tippen auf die Appverknüpfung ausgeführt wird. Aus dem AndroidManifest.xml, der unsicheren Beispielapp „InsecureBankv2“ sieht diese Activity folgendermaßen aus:
<activity android:name=".LoginActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity>
Die App weist in ihrem AndroidManifest.xml ein typisches Problem mit Activities auf. Eine exportierte Activity kann manuell über Android Debugging Bridge (ADB) oder auch über andere Apps auf dem Gerät gestartet werden. Die InsecureBankv2 App implementiert eine Activity nach dem Login, die nur nach erfolgreicher Anmeldung verfügbar sein sollte. Diese wird aber exportiert und ist somit ohne Anmeldung zugänglich.
<activity android:name=".PostLogin" android:exported="true" android:label="@string/title_activity_post_login" > </activity>
Intents werden im Normalfall für die Inter-Process Communication (IPC) verwendet, also für Kommunikation zwischen verschiedenen, aber auch innerhalb von einzelnen Apps.
Es gibt verschiedene Formen von Intents, die ihre jeweiligen Verwendungszwecke haben. Man kann sich Intents wie HTTP GET oder POST vorstellen, die ein bestimmtes Ziel aufrufen und Daten enthalten können, aber nicht müssen.
Hierbei kann man implizite oder explizite Intents durchführen. Bei impliziten Intents ist zu beachten, dass der Empfänger (App) nicht genau definiert wird, sondern die lediglich eine Aktion bestimmt wird, die durchgeführt werden soll, z. B.
Intent email = new Intent(Intent.ACTION_SEND, Uri.parse("mailto:example@secur.ai"));
Jede verfügbare App, die den passenden Intent-Filter in deren AndroidManifest.xml definiert hat, kann diese Aufrufe theoretisch erhalten. Beispielsweise:
<activity android:name="ExampleActivity"> <intent-filter> <action android:name="android.intent.action.SEND"/> <category android:name="android.intent.category.DEFAULT"/> </intent-filter> </activity>
Wenn also über Intents vertrauliche Informationen erhalten oder gesendet werden, muss der Empfänger eindeutig mit expliziten Intents definiert werden.
Ähnlich können auch Broadcasts definiert werden, die ebenfalls mit Vorsicht verwendet werden müssen. Werden keine expliziten Empfänger oder benutzerdefinierte Rechte definiert, kann theoretisch jede oder sogar mehrere Apps auf den Broadcast reagieren und eventuelle Daten abrufen. Sogenannte Sticky Broadcasts sind mit API 21 veraltet und sollten nicht verwendet werden, da diese keine Sicherheitsfunktionen bieten.
Die offizielle Dokumentation bietet Informationen zu Broadcast Sicherheit und Best Practices (siehe wichtige Links).
Bei Verwendung von Broadcast Receiver, Services, Service Providers und Deep Links (z. B. app://eigene/daten) ist besonders darauf zu achten, dass empfangenen Daten nicht vertraut werden darf.
WebViews erlauben die Verwendung des Android-Browsers in Apps. Immer häufiger wird dies für Apps verwendet, da die Entwicklung, aber auch Updates erleichtert werden. Da es sich dabei im Endeffekt um eine klassische Web-Applikation in Android-App-Form verpackt handelt, muss man dieselben Prinzipien wie bei einer Web-Applikation anwenden. Die OWASP Top 10 behandeln wir in diesem Blogartikel.
Die definierte minSdkVersion kann gleichgesetzt werden mit dem Minimum an Sicherheitsanpassungen in Android, auf dem die App laufen kann. Wenn also die SDK-Version (oder API Level), die ein Zielgerät haben muss, dass die App installiert werden kann, niedrig gehalten wird, um die Kompatibilität zu erhöhen, leidet darunter die Sicherheit.
Ist eine minSdkVersion von 11 definiert (Android 3.0), muss man davon ausgehen, dass ein Benutzer keine Sicherheitsvorkehrungen nach API Level 11 hat. Beispielsweise konnte vor API Level 16 jede App auf jegliche Logs ohne spezielle Rechte zugreifen. Ein weiteres Beispiel ist, dass in früheren API-Leveln extern gespeicherte Inhalte (SD-Karte) von jeder App gelesen werde konnten.
Frameworks und Bibliotheken von Drittanbietern erleichtern die Entwicklung ungemein und sind auch aus Sicht der Sicherheit meist von Vorteil. Natürlich macht es Sinn, auf diese zurückzugreifen und das Rad nicht neu zu erfinden, jedoch muss beachtet werden, dass dies nicht in ein Schneeballsystem verfällt. Wenn beispielsweise eine externe Bibliothek weitere externe Bibliotheken verwendet, kann das schnell aus dem Ruder laufen. Es ist sehr schwer dabei den Überblick zu behalten, man vergrößert wieder seine Angriffsfläche und Updateprozesse werden verkompliziert. Außerdem muss man sich unabhängig von der Sicherheit auch mit Lizenzen beschäftigen.
Die Verwendung von externen Bibliotheken sollte also in Maß und Relation zu der App gehalten werden.
Sicherheitsvorkehrungen wie Certificate Pinning, das Setzen des Secure Flag (z. B. um Screenshots zu unterbinden) oder des Debuggable Flag „False“ machen zwar im Normalfall durchaus Sinn, aber diese können von Angreifern relativ einfach umgangen werden.
Zusammenfassend lässt sich sagen, dass allgemein gültige Richtlinien für sichere Programmierung auch für Android gelten. Der öffentlichen Android-Leitfaden für Entwickler und sichere Entwicklung ist ein umfangreiches und essentielles Werk. Durch die Kombination aus Richtlinien zur sicheren Entwicklung und dem Android-Leitfaden wird somit die Grundlage für sichere Android-Apps gelegt, sodass auch bei unseren Penetrationstests keine bösen Überraschungen auf Sie warten sollten.