Advertisement
  1. Code
  2. Security

Schlüssel, Anmeldeinformationen und Speicher auf Android

by
Read Time:12 minsLanguages:

German (Deutsch) translation by Tatsiana Bochkareva (you can also view the original English article)

Im vorherigen Artikel zur Datensicherheit von Android-Benutzern haben wir uns mit der Verschlüsselung von Daten über einen vom Benutzer angegebenen Passcode befasst. In diesem Lernprogramm wird der Schwerpunkt auf die Speicherung von Anmeldeinformationen und Schlüsseln gelegt. Ich beginne mit der Einführung von Kontoanmeldeinformationen und ende mit einem Beispiel für den Schutz von Daten mithilfe des KeyStore.

Wenn Sie mit einem Drittanbieter arbeiten, ist häufig eine Authentifizierung erforderlich. Dies kann so einfach sein wie ein /login-Endpunkt, der einen Benutzernamen und ein Kennwort akzeptiert.

Zunächst scheint es eine einfache Lösung zu sein, eine Benutzeroberfläche zu erstellen, die den Benutzer auffordert, sich anzumelden, und dann seine Anmeldeinformationen zu erfassen und zu speichern. Dies ist jedoch nicht die beste Vorgehensweise, da unsere App die Anmeldeinformationen für ein Konto eines Drittanbieters nicht kennen muss. Stattdessen können wir den Account Manager verwenden, der die Verarbeitung dieser vertraulichen Informationen für uns delegiert.

Buchhalter

Der Account Manager ist ein zentraler Helfer für Anmeldeinformationen von Benutzerkonten, sodass Ihre App nicht direkt mit Kennwörtern umgehen muss. Es stellt häufig ein Token anstelle des tatsächlichen Benutzernamens und Kennworts bereit, mit dem authentifizierte Anforderungen an einen Dienst gestellt werden können. Ein Beispiel ist das Anfordern eines OAuth2-Tokens.

Manchmal sind alle erforderlichen Informationen bereits auf dem Gerät gespeichert, und manchmal muss der Account Manager einen Server anrufen, um ein aktualisiertes Token zu erhalten. Möglicherweise haben Sie den Abschnitt Accounts in den Einstellungen Ihres Geräts für verschiedene Apps gesehen. Wir können diese Liste der verfügbaren Accounts erhalten:

Der Code erfordert die Berechtigung android.permission.GET_ACCOUNTS. Wenn Sie nach einem bestimmten Account suchen, finden Sie es:

Sobald Sie den Account haben, können Sie ein Token für das Account abrufen, indem Sie die Methode getAuthToken(Account, String, Bundle, Activity, AccountManagerCallback, Handler) aufrufen. Das Token kann dann verwendet werden, um authentifizierte API-Anforderungen an einen Dienst zu senden. Dies kann eine RESTful-API sein, bei der Sie während einer HTTPS-Anforderung einen Token-Parameter übergeben, ohne jemals die Details des privaten Kontos des Benutzers kennen zu müssen.

Da für jeden Dienst die privaten Anmeldeinformationen auf unterschiedliche Weise authentifiziert und gespeichert werden, stellt der Account Manager Authentifizierungsmodule zur Verfügung, die von einem Drittanbieter-Service implementiert werden können. Während Android Implementierungen für viele beliebte Dienste bietet, können Sie Ihren eigenen Authentifikator schreiben, um die Kontoauthentifizierung und den Speicher für Anmeldeinformationen Ihrer App zu verwalten. Auf diese Weise können Sie sicherstellen, dass die Anmeldeinformationen verschlüsselt sind. Beachten Sie, dass dies auch bedeutet, dass Anmeldeinformationen im Account Manager, die von anderen Diensten verwendet werden, im Klartext gespeichert werden können, sodass sie für jeden sichtbar sind, der sein Gerät gerootet hat.

Anstelle einfacher Anmeldeinformationen müssen Sie manchmal einen Schlüssel oder ein Zertifikat für eine Person oder Entität verarbeiten, z. B. wenn Ihnen ein Dritter eine Zertifikatdatei sendet, die Sie aufbewahren müssen. Das häufigste Szenario ist, wenn sich eine App beim Server einer privaten Organisation authentifizieren muss.

Im nächsten Tutorial werden wir uns mit der Verwendung von Zertifikaten für die Authentifizierung und sichere Kommunikation befassen, aber ich möchte in der Zwischenzeit noch erläutern, wie diese Elemente gespeichert werden. Die Schlüsselbund-API wurde ursprünglich für diesen speziellen Zweck entwickelt: Installieren eines privaten Schlüssels oder Zertifikatpaars aus einer PKCS#12-Datei.

Der Schlüsselbund

Die in Android 4.0 (API Level 14) eingeführte Schlüsselbund-API befasst sich mit der Schlüsselverwaltung. Insbesondere funktioniert es mit PrivateKey- und X509Certificate-Objekten und bietet einen sichereren Container als die Verwendung des Datenspeichers Ihrer App. Dies liegt daran, dass Berechtigungen für private Schlüssel nur Ihrer eigenen App den Zugriff auf die Schlüssel ermöglichen und nur nach Benutzerautorisierung. Dies bedeutet, dass auf dem Gerät ein Sperrbildschirm eingerichtet werden muss, bevor Sie den Speicher für Anmeldeinformationen verwenden können. Falls verfügbar, sind die Objekte im Schlüsselbund möglicherweise an sichere Hardware gebunden.

Der Code zum Installieren eines Zertifikats lautet wie folgt:

Der Benutzer wird aufgefordert, ein Kennwort für den Zugriff auf den privaten Schlüssel und eine Option zum Benennen des Zertifikats einzugeben. Um den Schlüssel abzurufen, enthält der folgende Code eine Benutzeroberfläche, über die der Benutzer aus der Liste der installierten Schlüssel auswählen kann.

Sobald die Auswahl getroffen wurde, wird im alias(final String alias) ein String-Aliasname zurückgegeben, über den Sie direkt auf den privaten Schlüssel oder die Zertifikatkette zugreifen können.

Mit diesem Wissen wollen wir nun sehen, wie wir den Speicher für Anmeldeinformationen verwenden können, um Ihre eigenen vertraulichen Daten zu speichern.

Der KeyStore

Im vorherigen Tutorial haben wir uns mit dem Schutz von Daten über einen vom Benutzer angegebenen Passcode befasst. Diese Art der Einrichtung ist gut, aber die App-Anforderungen vermeiden oft, dass sich Benutzer jedes Mal anmelden und sich einen zusätzlichen Passcode merken.

Hier kann die KeyStore-API verwendet werden. Seit API 1 wird der KeyStore vom System zum Speichern von WLAN- und VPN-Anmeldeinformationen verwendet. Ab 4.3 (API 18) können Sie mit Ihren eigenen app-spezifischen asymmetrischen Schlüsseln arbeiten und in Android M (API 23) einen symmetrischen AES-Schlüssel speichern. Während die API das direkte Speichern vertraulicher Zeichenfolgen nicht zulässt, können diese Schlüssel gespeichert und dann zum Verschlüsseln von Zeichenfolgen verwendet werden.

Der Vorteil des Speicherns eines Schlüssels im KeyStore besteht darin, dass Schlüssel bearbeitet werden können, ohne den geheimen Inhalt dieses Schlüssels preiszugeben. Schlüsseldaten gelangen nicht in den App-Bereich. Denken Sie daran, dass Schlüssel durch Berechtigungen geschützt sind, sodass nur Ihre App darauf zugreifen kann. Wenn das Gerät in der Lage ist, sind sie möglicherweise zusätzlich sicherheitsunterstützt. Dadurch wird ein Container erstellt, der das Extrahieren von Schlüsseln von einem Gerät erschwert.

Generieren Sie einen neuen Zufallsschlüssel

In diesem Beispiel können wir anstelle eines AES-Schlüssels aus einem vom Benutzer angegebenen Passcode automatisch einen zufälligen Schlüssel generieren, der im KeyStore geschützt wird. Wir können dies tun, indem wir eine KeyGenerator-Instanz erstellen, die auf den Anbieter "AndroidKeyStore" eingestellt ist.

Wichtige Teile, die hier betrachtet werden müssen, sind die Spezifikationen .setUserAuthenticationRequired(true) und .setUserAuthenticationValidityDurationSeconds(120). Dazu muss ein Sperrbildschirm eingerichtet und der Schlüssel gesperrt werden, bis sich der Benutzer authentifiziert hat.

In der Dokumentation zu .setUserAuthenticationValidityDurationSeconds() sehen Sie, dass der Schlüssel nur eine bestimmte Anzahl von Sekunden nach der Kennwortauthentifizierung verfügbar ist und dass die Übergabe von -1 jedes Mal eine Authentifizierung per Fingerabdruck erfordert, wenn Sie auf den Schlüssel zugreifen möchten. Durch Aktivieren der Authentifizierungsanforderung wird der Schlüssel auch widerrufen, wenn der Benutzer den Sperrbildschirm entfernt oder ändert.

Da das Speichern eines ungeschützten Schlüssels neben den verschlüsselten Daten dem Platzieren eines Hausschlüssels unter der Fußmatte gleicht, versuchen diese Optionen, den Schlüssel in Ruhe zu schützen, falls ein Gerät kompromittiert wird. Ein Beispiel könnte ein Offline-Datendump des Geräts sein. Ohne dass das Kennwort für das Gerät bekannt ist, werden diese Daten unbrauchbar.

Die Option .setRandomizedEncryptionRequired(true) aktiviert die Anforderung, dass genügend Randomisierung vorhanden ist (jedes Mal eine neue zufällige IV), sodass die verschlüsselte Ausgabe immer noch unterschiedlich ist, wenn dieselben Daten ein zweites Mal verschlüsselt werden. Dies verhindert, dass ein Angreifer aufgrund der Eingabe derselben Daten Hinweise auf den Chiffretext erhält.

Eine weitere zu beachtende Option ist setUserAuthenticationValidWhileOnBody(boolean remainsValid), mit dem der Schlüssel gesperrt wird, sobald das Gerät erkannt hat, dass er sich nicht mehr in der Person befindet.

Daten verschlüsseln

Nachdem der Schlüssel im KeyStore gespeichert ist, können wir eine Methode erstellen, die Daten mit dem Cipher-Objekt unter Verwendung des SecretKey verschlüsselt. Es wird eine HashMap zurückgegeben, die die verschlüsselten Daten und eine zufällige IV enthält, die zum Entschlüsseln der Daten benötigt wird. Die verschlüsselten Daten können dann zusammen mit der IV in einer Datei oder in den freigegebenen Einstellungen gespeichert werden.

Entschlüsseln in ein Byte-Array

Bei der Entschlüsselung wird das Gegenteil angewendet. Das Cipher-Objekt wird mit der Konstante DECRYPT_MODE initialisiert und ein entschlüsseltes byte[] -Array zurückgegeben.

Beispiel testen

Wir können jetzt unser Beispiel testen!

Verwenden von asymmetrischen RSA-Schlüsseln für ältere Geräte

Das ist eine gute Lösung zum Speichern von Daten für Versionen M und höher. Wenn Ihre App frühere Versionen unterstützt? Während symmetrische AES-Schlüssel unter M nicht unterstützt werden, sind es asymmetrische RSA-Schlüssel. Wir können RSA-Schlüssel und Verschlüsselung verwenden, um dasselbe zu erreichen.

Der Hauptunterschied besteht darin, dass ein asymmetrisches Schlüsselpaar zwei Schlüssel enthält, einen privaten und einen öffentlichen Schlüssel, wobei der öffentliche Schlüssel die Daten verschlüsselt und der private Schlüssel sie entschlüsselt. Eine KeyPairGeneratorSpec wird an den KeyPairGenerator übergeben, der mit KEY_ALGORITHM_RSA und dem "AndroidKeyStore" -Anbieter initialisiert wird.

Zum Verschlüsseln erhalten wir den RSAPublicKey vom Schlüsselpaar und verwenden ihn mit dem Cipher-Objekt.

Die Entschlüsselung erfolgt mit dem RSAPrivateKey-Objekt.

Eine Sache bei RSA ist, dass die Verschlüsselung langsamer ist als in AES. Das geht für kleine Informationsmengen in Ordnung, z. B. wenn Sie gemeinsame Einstellungszeichenfolgen sichern. Wenn Sie jedoch ein Leistungsproblem beim Verschlüsseln großer Datenmengen feststellen, können Sie dieses Beispiel stattdessen zum Verschlüsseln und Speichern nur eines AES-Schlüssels verwenden. Verwenden Sie dann die schnellere AES-Verschlüsselung, die im vorherigen Lernprogramm für den Rest Ihrer Daten beschrieben wurde. Sie können einen neuen AES-Schlüssel generieren und ihn in ein byte[] -Array konvertieren, das mit diesem Beispiel kompatibel ist.

Gehen Sie folgendermaßen vor, um den Schlüssel von den Bytes zurückzugewinnen:

Das war viel Code! Um alle Beispiele einfach zu halten, habe ich auf eine gründliche Ausnahmebehandlung verzichtet. Denken Sie jedoch daran, dass es für Ihren Produktionscode nicht empfohlen wird, einfach alle Throwable-Fälle in einer catch-Anweisung abzufangen.

Abschluss

Damit ist das Lernprogramm zum Arbeiten mit Anmeldeinformationen und Schlüsseln abgeschlossen. Ein Großteil der Verwirrung um Schlüssel und Speicher hängt mit der Entwicklung des Android-Betriebssystems zusammen. Sie können auswählen, welche Lösung von Ihrer App unterstützten API-Ebene verwendet werden soll.

Nachdem wir die Best Practices für das Sichern von Daten in Ruhe behandelt haben, konzentriert sich das nächste Lernprogramm auf das Sichern von Daten während des Transports.

Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.