BSI-Veröffentlichungen zur Cyber-Sicherheit EMPFEHLUNG: IT-HERSTELLER Sichere Softwareentwicklung unter Android Smartphones und Tablets gewinnen als tägliche Begleiter zunehmend an Bedeutung. Gleichermaßen steigen auch die Anforderungen an die IT-Sicherheit dieser Geräte. Natürlich sollte die Plattform bzw. das Betriebssystem (z. B. Apple iOS oder Google Android) selbst möglichst sicher konzipiert sein. Ergänzend müssen allerdings die Anwendungen, sogenannte Apps, sorgsam und unter Beachtung grundsätzlicher Regelungen entwickelt werden. Andernfalls kann selbst eine sichere Plattform durch Schwachstellen in Anwendungen kompromittiert werden. Mit Java als Programmiersprache finden Entwickler einen schnellen Einstieg in die Entwicklung von Apps für das Betriebssystem Android. Allerdings unterscheidet sich das Sicherheitskonzept von Android und dessen Java-Implementierung (DalvikVM) grundlegend von dem der konventionellen Java Laufzeitumgebung. So ist die DalvikVM sehr viel enger mit dem Betriebssystem verbunden und auch native Codeteile sind besser geschützt. Daher ist von App-Entwicklern auch immer ein hinreichendes Detailwissen zu den sicherheitsrelevanten Spezifika der Android Plattform gefordert. Dieses Dokument gibt Empfehlungen zur Entwicklung sicherer Anwendungen für das Betriebs­ system Android. Die Empfehlungen richten sich an App-Entwickler, denen die Grundlagen und Begrifflichkeiten der Android Plattform1 bekannt sind. Die folgenden Aspekte werden behandelt: 1. Allgemeines und Architektur 2. Essenzielle Android-Bausteine 3. Anwendungsebene 4. Testen, Paketierung und Distribution Allgemeines und Architektur Bereits bei der Konzeption der Architektur der Apps ist das Minimalitätsprinzip bzgl. erforderlicher Rechte und zu verarbeitenden bzw. zu erfassenden Daten zu befolgen. Sämtliche Daten sollten sicher gespeichert werden. Dabei bieten sich je nach Anwendungsfall eine lokale Datenhaltung oder eine Speicherung auf zugehörigen Serverkomponenten an. In beiden Fällen sollten die Daten möglichst kryptografisch geschützt werden. Es ist zu empfehlen, sämtliche Eingabedaten nicht ungeprüft zu verarbeiten, sondern stets einer strikten Eingabevalidierung zu unterziehen. Dies gilt u. a. für Daten aus dem Internet, Nutzereingaben, Aufrufe durch andere Apps, SMS-Inhalte, Bluetooth-Datenpakete, Protokolldaten usw. Die Architektur der Software sollte prinzipiell die Installation von Sicherheitspatches ermöglichen. Zudem ist eine angemessene automatische Speicherung von Informationen zu bestimmten 1 http://developer.android.com/ BSI-CS 014 | Version 1.00 vom 30.07.2012 Seite 1 von 6 BSI-Veröffentlichungen zur Cyber-Sicherheit | Sichere Softwareentwicklung unter Android Ereignissen ratsam. Auch hier gilt das Minimalitätsprinzip – insbesondere mit Hinblick auf das Aufzeichnen sensitiver Nutzerdaten in Logdateien sowie Performanzaspekte. In der Regel verwenden Apps Drittkomponenten in Form von verschiedensten Bibliotheken. Diese sollten ausschließlich aus vertrauenswürdigen Quellen bezogen und hinsichtlich der geltenden Softwarelizenzen geprüft werden. Darüber hinaus sollten Wartung, Pflege und Support für diese Bibliotheken sichergestellt sein. Wie für die eigenen Codeteile der App ist auch für die verwendeten Bibliotheken eine zeitnahe Aktualisierung vorzunehmen, falls Sicherheitspatches verfügbar sind. Das Exception Handling sollte lückenlos implementiert sein. Die lokale und möglichst spezifische Behandlung von Exceptions ist vorzuziehen. Globale Catch-all Klauseln können zusätzlich sämtliche nicht zuvor aufgefangenen Exceptions verarbeiten. Weiterhin hat es sich in der Praxis als sinnvoll erwiesen, dass Apps eigenständig untersuchen, ob es Hinweise auf ein Rooting des benutzten Geräts gibt. Sicherheitskritische Apps sollten in diesem Falle ihre Funktionsfähigkeit einschränken oder den Dienst verweigern. Eine verlässliche Erkennung gerooteter Geräte ist allerdings nicht möglich. Mit Android 2.2 wurde erstmals das Konzept der Device Administration eingeführt, mit der Apps im Kontext einer Security Policy betrieben werden können. Dieses Konzept ist – bei entsprechendem Anwendungsfall – zu unterstützen. Das unter Entwicklern übliche Verfahren der „copy and paste“-Programmierung, bei dem Programmcode aus externen Quellen wiederverwendet wird, sollte nicht bedenkenlos angewendet werden. Insbesondere bei größeren Programmteilen sollte eine kritische Prüfung der kopierten Code-Zeilen auf Fehler oder unerwünschte Funktionen durchgeführt werden. Essenzielle Android-Bausteine Permissions Für Berechtigungen gilt das Minimalitätsprinzip sowohl für die von der App eingeforderten Rechte (usespermissions) als auch für die von der App selbst definierten Rechte (Permissions). Für selbst definierte Permissions sind einfache Bezeichner und Erläuterungen zu wählen, die den Nutzer nicht überfordern. Bezeichner und Erläuterungen sollten darüber hinaus auf Mehrsprachigkeit ausgelegt sein (Localization). Das protectionLevel einer selbst definierten Berechtigung ist sorgfältig festzulegen, damit keine trügerische Sicherheit resultiert. Wird eine selbst definierte Permission lediglich durch eigene Apps desselben Entwicklers genutzt, so ist evtl. das protectionLevel “Signature“ ausreichend. In vielen anderen Fällen ist “Dangerous“ sinnvoll – insbesondere wenn durch diese Permission eine Activity abgesichert wird, über die z. B. indirekt ein Internetzugriff möglich ist. Im Einzelfall ist abzuwägen, ob eine Permission für eine Aktion erforderlich ist oder ob alternative Umsetzungsmöglichkeiten existieren. Beispielsweise kann eine Permission für den Zugriff auf Daten in einer Datenbank durch eine App exklusiv über eine Activity realisiert werden, welche eine Bestätigung des Nutzers einholt. Hier werden sonst häufig externe Intents definiert. Dadurch sind weniger Permissions für eine App erforderlich und die Übersichtlichkeit bzw. Transparenz für den Nutzer wird erhöht. Intents Intents stellen das zentrale Element der Inter-Prozess-Kommunikation (IPC) unter Android dar und spielen daher eine besondere Rolle bzgl. der Sicherheit einer App. Empfänger von Intents, also Activities, Services und BroadcastReceiver, müssen Vorkehrungen gegen bösartige oder manipulierte Intents treffen. Insbesondere ist zu beachten, dass die zur Vermittlung von BSI-CS 014 | Version 1.00 vom 30.07.2012 Seite 2 von 6 BSI-Veröffentlichungen zur Cyber-Sicherheit | Sichere Softwareentwicklung unter Android Intents verwendeten IntentFilter in Android keine Parametervalidierung durchführen, sondern nur der Vermittlung auf der Ebene des Betriebssystems dienen. Darüber hinaus werden Intents ohne explizit gesetzte Kategorien bei passender Aktion durchgelassen, auch wenn der Intent Filter diese Kategorie nicht enthält. Die Filterung der Attribute eines Intents sollte deklarativ über das Manifest erfolgen (z. B. Aktion, Kategorie, Schema). Dies ist einfach umzusetzen und führt zu einer Prüfung auf OS-Ebene. Zudem sollte eine pragmatische Filterung der Attribute eines Intents implementiert werden. Hierzu gehört eine Prüfung bzgl. dem Vorhandensein aller erwarteten bzw. Nicht-Vorhandensein von nicht-erwarteten Key-Value-Paaren – sogenannte Extras – eine Prüfung der URI-Formate sowie der Datentypen der Extra-Werte und der DefaultKategorien. Des weiteren sollte der Absender des Intents geprüft werden. Der Paketname kann allerdings nur validiert werden, wenn der aufrufende Intent einen Rückgabewert akzeptiert. Häufig werden durch aufgerufene Komponenten (z. B. Activity) einer App automatisch Intents angestoßen. Sind diese Komponenten von außen – also durch andere Apps – zugreifbar, so muss besonders darauf geachtet werden, dass hierdurch keine ungewollten Intents durch die eigene App gesendet werden können. Ansonsten könnte eine bösartige App das eigene Programm nutzen, um einen Intent zu senden, für welchen die bösartige App selbst nicht über die erforderlichen Berechtigungen verfügt. In einem solchen Fall bietet sich statt normalen Intents die Verwendung von PendingIntents an, da bei Letzteren der Callback so behandelt wird, als käme er vom Absender des (Pending)Intents. Somit gelten für die mit dem Intent ausgelösten Aktivitäten dieselben Rechte, wie für die aufrufende App. PendingIntents sollten mittels setComponent() an die jeweilige Komponente gebunden werden. Activities Activities bilden die Grundlage für die Benutzeroberfläche einer App. Besitzen sie das Attribut android:exported=“true“ (default), können sie von anderen Apps mit beliebigen Intents über entsprechend definierte Parametrierung von action, data, category oder extras gestartet werden. Ist nicht erwünscht, dass andere Apps eine Activity initiieren können, sollte sie mit dem Attribut android:exported=“false“ versehen werden. Am sichersten sind Activities ohne IntentFilter und mit android:exported=“false“, da diese nicht mittels Context.startActivity(Intent i) aufgerufen werden können. Bei der Kommunikation zwischen Activities derselben App sollten daher möglichst nur explizite Intents (d. h. mit Angabe der Klasse, welche die jeweilige Activity implementiert) mittels Intent.setComponent() verwendet werden. Die dadurch gewonnene Sicherheit führt allerdings zu der Einschränkung, dass diese Activities nicht durch andere Apps (bzw. Apps anderer Autoren) verwendet werden können. Wenn keine expliziten Intents infrage kommen, sollten in jedem Fall geeignete Permissions festgelegt werden. Beim Aufruf von Activities empfiehlt es sich, dass möglichst keine kritischen Daten als Teil der Intents mitgegeben werden, damit ein Angreifer nicht einen höher priorisierten IntentFilter registriert und diese Informationen abfängt. Wenn eine kritische Activity durch ein Intent gestartet wird, sollte ggf. eine Bestätigung durch den Nutzer eingeholt werden oder eine Absicherung durch Permissions (Attribut android:permission) erfolgen. Somit können nur Apps mit der jeweiligen Permission diese Activity aufrufen. Dabei können sowohl vordefinierte Berechtigungstypen genutzt als auch eigene definiert werden. Sicherheitskritische Apps werden häufig mit einem Lock (z. B. PIN-Eingabe) versehen. In solchen Fällen ist es wichtig, dass in jeder (von außen zugänglichen) Activity geprüft wird, ob dieser Lock aufgehoben wurde. Andernfalls sollte zunächst ein automatischer Aufruf der Activity erfolgen, die für das Aufheben des Locks zuständig ist. BSI-CS 014 | Version 1.00 vom 30.07.2012 Seite 3 von 6 BSI-Veröffentlichungen zur Cyber-Sicherheit | Sichere Softwareentwicklung unter Android Broadcasts & Receiver Broadcasts sind Intents, die nicht für einen Empfänger bestimmt sind, sondern systemweit gelesen werden können. Für BroadcastReceiver müssen geeignete Permissions definiert werden, damit nicht beliebige Apps entsprechende Broadcasts versenden können. Zum Senden sicherer Broadcast Intents sollte broadcastIntent() mit entsprechenden receiverPermissions versehen werden, über die der Empfänger verfügen muss. StickyBroadcasts können nicht mit einer Permission versehen werden. Somit ist es möglich, sie von jeder App zu versenden und auch zu fälschen. StickyBroadcasts gewährleisten zudem nicht die Zustellung, da jede App mit dem Recht BROADCAST_STICKY beliebige StickyBroadcasts löschen kann. Daher sollte diese Art von Broadcasts nicht verwendet werden. Services Services dienen der Abarbeitung von Aufgaben im Hintergrund, ohne dass diese eine direkte Interaktion mit dem Benutzer ermöglichen. Services können durch die Validierung der Rechte des Aufrufenden bei onServiceConnected() mittels des folgenden Aufrufs abgesichert werden: GetPackageManager().checkPermission(permissionToCheck, name.getPackageName()); Zur Gewährleistung der Performanz und Stabilität einer App sollte der Service – insbesondere bei Ressourcen-intensiven Aufgaben – explizit als separater Thread angelegt werden. Andernfalls kann der Service die App beeinträchtigen und dazu führen, dass diese nicht mehr reagiert. Content Providers Bei Android werden Daten üblicherweise in einer SQLite-Datenbank verarbeitet. Der Zugriff auf diese Datenbank erfolgt nicht direkt aus der Anwendungslogik, sondern über sogenannte Content Provider, welche den Datenzugriff als Dienst über die darin implementierten Methoden anbieten. Bei SQLite-basierten Content Providern ist es – analog zu konventionellen Webanwendungen – erforderlich, geeignete Maßnahmen gegen SQL-Injections zu treffen: • Filterung bzw. Validierung von Parametern • Verwendung von parametrisierten Queries zur Trennung zwischen SQL-Logik und Daten • Deklaration von selection Strings als final • Vollständiger Verzicht auf “händische“ Erstellung von SQL-Queries auf String-Ebene SQL-Statements sollten nicht zur Laufzeit zusammengesetzt werden. Bevorzugt ist die parametrierte Methode db.query() zu verwenden, da hier die Parameter separat angegeben werden können. SQLKonstrukte, die in diesen Parametern enthalten sind, werden somit als Strings und nicht als SQL-Statement behandelt. Die Verwendung von executeSQL(...) ist zu vermeiden, da hier die Ausnutzung einer SQLInjection-Schwachstelle am wahrscheinlichsten ist. Für die Content Provider sollten die jeweiligen Permissions im Manifest angegeben werden, damit diese durch die Plattform umgesetzt werden und somit der Zugriff beschränkt wird. Auch wenn eine Komponente nur über Schreibrechte auf eine Datenbank verfügt, so können mittels sukzessiver Aufrufe mit geschickt gewählten WHERE-Klauseln Rückschlüsse auf die Inhalte einer Datenbank gezogen werden. Daher sollten Schreibrechte auf einen (SQL-)Provider prinzipiell so eingestuft werden wie Lese-&Schreibrechte. Sämtliche Zugriffsberechtigungen auf Datenbanken bzw. Content Provider sollten möglichst restriktiv vergeben werden. Zudem empfiehlt sich, im Content Provider geeignete Filtermethoden zu implementieren. BSI-CS 014 | Version 1.00 vom 30.07.2012 Seite 4 von 6 BSI-Veröffentlichungen zur Cyber-Sicherheit | Sichere Softwareentwicklung unter Android Das dynamische Gewähren und Widerrufen von Zugriffsrechten über den Paketnamen sollte vermieden werden, d. h. auf folgende Konstrukte ist zu verzichten: • android:grantUriPermission=“true“ und darauffolgende <grant-uri-permission> im Manifest sowie grantUriPermission() im Code • Intents mit FLAG_GRANT_READ_URI_PERMISSION, FLAG_GRANT_WRITE_URI_PERMISSION Anwendungsebene Umsetzung von Benutzeroberflächen Prinzipiell sind Benutzeroberflächen – insbesondere Activities – so zu gestalten, dass Nutzer nicht zu unbeabsichtigten Aktionen oder zu einer unsicheren Konfiguration verleitet werden. Hierzu gehören insbesondere sichere Default-Parameter und eine sichere Nutzerführung inkl. kontextsensitiver Hilfselemente. Über die Eigenschaft inputType der verschiedenen GUI-Elemente sollte die Art der eingegebenen Daten eingeschränkt werden, um Fehleingaben zu verhindern. Eine anschließende Überprüfung der eingegebenen Daten ist zu empfehlen (Validierung der Eingabedaten). Eine App sollte eine gut sichtbare Kontaktmöglichkeit für Sicherheitsvorfälle enthalten, die der Anwender nutzen kann. Zudem sollten kontextsensitive Hilfeelemente enthalten sein. Insbesondere sollte vor dem Aufruf kostenpflichtiger Funktionen die explizite Zustimmung des Nutzers gefordert werden. Gleichermaßen ist die Einwilligung des Nutzers bzgl. Allgemeiner Geschäftsbedingungen (AGB), Datenschutzbestimmungen und anderen Regelungen einzuholen. Dies hat bevorzugt zum Installationszeitpunkt bzw. bei der ersten Verwendung zu erfolgen. Darüber hinaus sollte dem Nutzer die Möglichkeit gegeben werden, seine Zustimmung zu widerrufen (Opt-Out), sodass die App anschließend die betroffenen Funktionen nicht mehr anbieten. Kommunikation mit serverseitigen Komponenten Wie bei Intents und GUI-Eingaben ist auch bei der Kommunikation mit Serverkomponenten eine strikte Eingabe-Validierung erforderlich. Prinzipiell sind sämtliche Verbindungen (Internet, SMS, Bluetooth, etc.) als unsicher anzusehen und mit geeigneten Mechanismen zu schützen. Daher sollte die Kommunikation über das Internet möglichst immer mittels SSL/HTTPS abgesichert werden. Hierzu kann entweder die entsprechende Java Standardbibliothek oder der Apache HttpClient verwendet werden. Entsprechende Zertifikate müssen ggf. installiert werden, sofern deren Wurzel nicht im Zertifikatsspeicher von Android enthalten ist. Dies erfolgt durch das Hinzufügen als Ressource (vor Android 4) bzw. über eine KeyChain (ab Android 4). Hostnames sollten stets explizit auf Übereinstimmung mit dem im Zertifikat angegebenen Servernamen geprüft werden, ebenso wie das SSL-Zertifikat. Auf die Implementierung unsicherer HostVerifier ist zu verzichten. Apps sollten möglichst auf eigene Server Sockets verzichten, d. h. nicht auf eigenen Ports lauschen und Verbindungsanfragen annehmen. Auch serverseitig sollten geeignete Sicherheitsmechanismen umgesetzt werden wie beispielsweise folgende: • Gewährleistung der sicheren Kommunikation (z. B. bei REST) • Härtung der Serverkomponenten • Authentisierung von API-Aufrufen (insbesondere bei kostenpflichtigen Diensten) • Monitoring der Servicenutzung hinsichtlich Anomalien (insbesondere bei kostenpflichtigen Diensten) • Regelmäßige Sicherheitsanalysen der verwendeten Softwarekomponenten und implementierten Schnittstellen BSI-CS 014 | Version 1.00 vom 30.07.2012 Seite 5 von 6 BSI-Veröffentlichungen zur Cyber-Sicherheit | Sichere Softwareentwicklung unter Android Authentisierung, Autorisierung und Session Management Prinzipiell sollten nur hinreichend sichere Authentisierungsmechanismen verwendet werden. Im Falle von Passwort-basierter Authentisierung sollten Passwort-Policies vorgegeben und durch die Programmlogik durchgesetzt werden. Sofern praktikabel sind alternative, Token-basierte Verfahren wie z. B. OAuth zu verwenden. Hinsichtlich der Verwendung von Passwörtern und Token gelten die folgenden Grundsätze: • Keine Speicherung im Cache, in Logdaten oder in Backup-Dateien • Verschlüsselte Speicherung; nicht extern lesbar • Keine Verteilung über SMS oder andere offene Kanäle • Keine Speicherung im Programmcode, da einfaches Reverse Engineering möglich Grundsätzlich ist zu prüfen, ob die Speicherung von Passwörtern überhaupt notwendig ist oder ob Hashwerte ausreichen. Files & Preferences Apps sollten ihre Daten nicht auf der SD-Karte speichern, weil sie dort nicht verschlüsselt werden. Soll trotzdem die SD-Karte als Speichermedium eingesetzt werden, ist zu beachten, dass dort VFAT als Dateisystem zum Einsatz kommt und somit die Linux-typischen File Permissions nicht greifen. Ab Android 3 kann die Partition /data, die auf der SD-Karte liegt, verschlüsselt werden. Rechte auf Dateien sind möglichst restriktiv zu vergeben, z. B. bei Methodenaufrufen wie fos = openFileOutput(“file“, Context.MODE_PRIVATE); Insbesondere kritische Dateien (z. B. Logfiles) dürfen keinesfalls MODE_WORLD_WRITEABLE deklariert sein. Verwendet eine App externe Dateien, die beispielsweise von anderen Apps zugreifbar sind oder über das Internet bezogen werden, so ist stets in der Entwurfs- und Entwicklungsphase der App auszuschließen, dass eine (von außen erfolgte) Änderung der Dateien zu einer Schwachstelle führt. Testen, Paketierung und Distribution Prinzipiell sollte vermieden werden, dass mehrere Apps eines Entwicklers bzw. Distributors mit dem gleichen Zertifikat signiert werden, um unter derselben UID zu laufen. Der private Schlüssel zum Signieren der App muss besonders geschützt werden. Andernfalls könnte ein Angreifer z. B. eine App entwickeln, die auf andere Apps Zugriff hat, weil diese mit dem gleichen Zertifikat signiert wurden. Damit ein Angreifer nicht ohne größere Aufwände ein Reverse Engineering einer App durchführen kann, empfiehlt sich eine Code Obfuscation. Hierzu ist im SDK das Tool ProGuard enthalten. Allerdings sei darauf hingewiesen, dass Code Obfuscation Reverse Engineering lediglich aufwändiger macht, es aber nicht verhindert. Vor der Paketierung einer App muss sämtlicher Code aus Entwicklungs- oder Testzweigen entfernt werden. Apps sollten mittels statischer und ggf. auch dynamischer Codeanalyse auf Schwachstellen hin untersucht werden. Darüber hinaus sind Schnittstellen ggf. mittels Fuzzing-Methoden zu testen. Tests auf Anwendungsebene sollten stets sowohl mit den Rechten eines Standardbenutzers als auch mit denen eines privilegierten Benutzers erfolgen. Auf der Kommunikationsebene empfiehlt sich, eine Analyse hinsichtlich unbeabsichtigter Datenlecks (z. B. über Metainformationen von Bildern) durchzuführen. Mit den BSI-Veröffentlichungen publiziert das Bundesamt für Sicherheit in der Informationstechnik (BSI) Dokumente zu aktuellen Themen der Cyber-Sicherheit. Kommentare und Hinweise können von Lesern an [email protected] gesendet werden. BSI-CS 014 | Version 1.00 vom 30.07.2012 Seite 6 von 6