Startseite / Artikel

Biometrische Erweiterung der Authentifizierung auf iOS und Android mit hardwaregebundenen Schlüsseln

Face ID allein beweist Ihrem Server nichts. Verwenden Sie Secure Enclave sowie Android Keystore-Schlüssel, um einmalige Anfragen zu signieren, um eine echte zusätzliche Authentifizierung zu gewährleisten.

Verlag: REACTAPP.TOP12 Min. Lesezeit2762 Wörter

Quellen: Biometrics, the Secure Enclave, and Auth Tokens: Three Ideas That Sound the Same But Aren’t

Die Produktbeschreibungen besagen oft „Face ID entsperrt die App“, und für Nutzer reicht diese Beschreibung aus. Für Teams, die Zahlungen, Gesundheitsdaten, Admin-Konsolen oder einen Anmeldeprozess entwickeln, wird dadurch der wichtige Aspekt übersehen: Eine biometrische Scans erreicht niemals den Backend-Teil, erzeugt keinen Token und übermittelt dem Code auch kein Gesichts- oder Fingerabdruckmuster. Was eine gut gestaltete App tatsächlich erhält, ist die Erlaubnis, geschütztes Hardware-Zubehör zur Verwendung eines privaten Schlüssels zu nutzen, den der Code nicht lesen kann; dieser Schlüssel kann anschließend eine einmalige Anfrage signieren, die der Server dann überprüft. Diese Anleitung unterscheidet die drei oft miteinander verwechselten Konzepte (biometrische Anfragen, hardwarebasierte Schlüssel und Authentifizierungstoken) und zeigt einen Registrierungs-und-Signierungsprozess auf beiden Plattformen auf.

Warum ein Token allein eine schwache Garantie auf einem Mobilgerät darstellt

Eine Mobile-App läuft auf dem von dem Benutzer kontrollierten Hardware, nicht auf Ihrem. Handys gehen verloren, Bildschirme können von anderen benutzt werden, während Entwicklungswerkzeuge hinzugefügt werden, und ein gerootetes oder jailbreaktes Gerät kann weitaus mehr Informationen über Ihre Prozesse preisgeben, als Ihnen lieb ist.

Trotz all dessen muss ein sensibler Endpunkt einem präzisen Behauptung vertrauen: Der Anruf stammt von einem Handy, das einen Schlüssel enthält, den der Server zuvor registriert hat, und von einer Person, die vor Kurzem mit diesem Schlüssel autorisiert wurde.

Vergleichen Sie das mit „Diese Anfrage enthält ein Token“. Jeder Wert, der im Speicher oder in der Anwendungsdatenbank gespeichert ist, kann kopiert und von einem anderen Ort aus erneut verwendet werden. Ein privater Schlüssel, der innerhalb geschützter Hardware generiert wird und niemals exportiert werden kann, ist ein viel schwierigeres Ziel, denn sein Stehlen bedeutet, die Hardware anzugreifen statt nur einen String zu lesen.

Bevor man etwas entwickelt, hilft es, klarzustellen, was jeder Bestandteil nachweisen soll:

  • Biometrische Authentifizierung: Das Telefon akzeptiert Face ID, Touch ID oder eine leistungsstarke Android-Biometrie.
  • Sichere Hardware-Schlüssel: Ein geschützter Privatschlüssel erzeugt eine Signatur.
  • Authentifizierungs-Token: Ihr Server gewährt eine Sitzung oder bestimmten Zugriff.

Ein robuster Entwurf nutzt alle drei Methoden, wobei jede für ihre eigene Aufgabe dient.

HTTPS schützt den Kommunikationskanal, nicht die Identität

HTTPS verschlüsselt den Datenverkehr zwischen der App und Ihrer API, sodass jemand, der das WLAN eines Cafés nutzt, die Anfragen nicht einfach lesen oder verfälschen kann.

phone ── encrypted HTTPS connection ──► server

Es ist zwingend erforderlich, reicht aber allein nicht aus. Wenn ein Angreifer bereits ein gültiges Token erlangt hat, übermittelt TLS dieses gestohlene Token zuverlässig und sicher an Ihren Server. In der verschlüsselten Verbindung gibt es keine Hinweise dafür, ob das Token vom legitimen Gerät stammt oder von einer Kopie.

Die Grundvoraussetzungen sind daher: Verwendung von HTTPS bei jedem Aufruf, Überprüfung der Zertifikate auf normale Weise, Aufrechterhaltung eines aktualisierten TLS-Stacks sowie die Hinzufügung eines Authentifizierungsmechanismus, der etwas Überprüfbares über das Gerät und die Handlung des Benutzers angibt.

Zertifikatspinning ist ein eingeschränktes Werkzeug

Durch das Pinning wird die App auf ein bekanntes Zertifikat oder eine öffentliche Schlüsselidentität beschränkt. In streng kontrollierten Apps kann dies bestimmte Man-in-the-Middle-Szenarien verringern.

Es kann jedoch nicht dazu führen, dass ein Token sich wie eine hardwarebasierte Authentifizierungsdatenquelle verhält. Zudem birgt es echte Betriebsrisiken: Wenn ein falsches Pin verwendet wird oder eine Zertifikatsrotation übersehen wird, hört jede installierte Version der App sofort auf, mit Ihrer API zu kommunizieren. Wenden Sie es nur an, wenn Ihr Bedrohungsmodell dies rechtfertigt und Ihr Release-Prozess eine zuverlässige Schlüsselrotation ermöglicht – betrachten Sie es niemals als Ersatz für gerätegebundene Authentifizierung.

Eine biometrische Anfrage ist lediglich ein lokales Ja oder Nein

Auf iOS bittet die App den LAContext, das Systemauthentifizierungsformular anzuzeigen; auf Android entspricht dem der BiometricPrompt. Das Betriebssystem führt die Scannung durch und gibt Erfolg oder Misserfolg zurück. Der folgende Auszug ist in Swift: Er prüft die Richtlinie, die nur Biometrie verwendet, zusammen mit einem Begründungstext und startet den Datentransfer, falls die Prüfung erfolgreich ist.

let context = LAContext()
let policy = LAPolicy.deviceOwnerAuthenticationWithBiometrics
context.evaluatePolicy(policy, localizedReason: "Approve this transfer") { success, error in
    guard success else { return }
    startTransfer()
}

Ihr Code erhält niemals Informationen zur Gesichtsgeometrie oder zu Fingerscann-Bildern. Apple beschreibt LocalAuthentication als eine Funktion, die mit dem Secure Enclave zusammenarbeitet und der App lediglich ein Erfolgs-/Misserfolgsresultat zurückgibt (Referenz zum LocalAuthentication-Framework).

Das reicht völlig aus, um privaten Inhalt innerhalb der App zu schützen. Als Beweismittel für einen Server hingegen reicht es aus drei Gründen nicht aus:

  • Das Ergebnis besagt lediglich „das Gerät hat die Überprüfung akzeptiert“; es enthält keine Informationen darüber, wer oder welches Konto betroffen ist.
  • Die Backend-Systeme haben keine Möglichkeit, einen auf der Client-Seite erzeugten Booleschen Wert zu überprüfen.
  • Falls der App-Prozess kompromittiert ist, kann ein Angreifer den Callback überspringen oder fälschen und einfach einen bereits vorhandenen Token wiederverwenden.

Die wichtige Erkenntnis aus diesem Muster ist, dass success lediglich ein Flag in Ihrem eigenen Speicherbereich ist. Ein robustereres Design nutzt die biometrische Überprüfung, um eine einzige kryptografische Operation zu entsperren, deren Ausgabe der Server unabhängig überprüfen kann.

Hardware-Schlüsselspeicher halten den Privatschlüssel außerhalb Ihres Prozesses

Apple-Geräte verfügen über den Secure Enclave, ein isoliertes Untersystem, das private Schlüssel erzeugen und verwenden kann, ohne die Rohdaten der Schlüssel jemals dem Hauptanwendungsprozessor zur Verfügung zu stellen. Laut Apples Dokumentation bleiben die Schlüssel im Secure Enclave, und die Anwendung erhält lediglich Ausgaben wie Signaturen (Apples Leitfaden zum Secure Enclave).

Die Entsprechung auf der anderen Plattform ist der Android Keystore. Je nach Hardware können Schlüssel durch eine Trusted Execution Environment (TEE) oder durch ein spezielles StrongBox-Sicherheitselement abgesichert werden. Seien Sie hier bei der Benennung vorsichtig: „Titan M“ ist das Chip in Google Pixel-Telefonen, keine allgemeine Android-API, und man sollte nicht annehmen, dass jedes Gerät eines besitzt. Aus Sicht der App ist entscheidend, wie ein Schlüssel abgesichert wird und welche Nutzungsvorschriften man ihm zuweist.

Für eine hochwertige Aktion sollte der Schlüssel vier Kriterien erfüllen:

  1. Er wird auf diesem spezifischen Gerät generiert.
  2. Jede Nutzung erfordert eine neue, starke biometrische Authentifizierung.
  3. Der private Teil darf niemals exportiert werden.
  4. Nur der öffentliche Schlüssel wird auf dem Server gespeichert.

Auf Android kann BiometricPrompt.CryptoObject eine Kryptoverarbeitung nur dann einschränken, wenn die Authentifiziererklasse BIOMETRIC_STRONG ist und der Schlüssel so konfiguriert werden kann, dass bei jeder Verwendung eine erneute Genehmigung erforderlich ist (BiometricPrompt-Dokumentation, Überblick über den Keystore).

Das Protokoll: Schlüssel einmal registrieren, anschließend neue Herausforderungen signieren

Das gesamte Verfahren umfasst zwei Phasen: Registrierung und Nutzung.

Registrierung

  1. Die App erzeugt ein vom Hardware-Modul unterstütztes Schlüsselpaar.
  2. Sie lädt den öffentlichen Schlüssel über HTTPS an den Backend-Server hoch.
  3. Der Server speichert den öffentlichen Schlüssel zusammen mit dem Konto und einem Geräteidentifikator.
  4. Der private Schlüssel bleibt auf dem Telefon, innerhalb sicherer Hardware.

Das Senden der öffentlichen Schlüssel ist unbedenklich: Sie kann Signaturen überprüfen, aber nicht erstellen. Nur der private Schlüssel kann signieren, und er verlässt niemals das gesicherte Hardware-Gerät.

Ausführung einer sensiblen Anfrage

  1. Die App bittet den Server um eine einmalige, zufällig generierte Herausforderung.
  2. Der Benutzer führt die biometrische Anfrage aus.
  3. Die sichere Hardware signiert die Herausforderung.
  4. Die App gibt die ID der Herausforderung sowie die Signatur zurück.
  5. Der Server überprüft die Signatur anhand des gespeicherten öffentlichen Schlüssels.
  6. Der Server akzeptiert oder lehnt die Aktion ab und kann anschließend ein Token ausstellen.

Die Herausforderung besteht darin, dass bei den meisten Implementierungen Fehler auftreten. Die Signatur muss zufällig sein, schnell ablaufen und genau einmal verwendet werden können. Zudem sollte sie mit dem Konto, der spezifischen Geräte-Identifikationsnummer sowie der genehmigten Aktion verknüpft sein (zum Beispiel „200 EUR auf Konto X überweisen“). Wenn eine dieser Bedingungen nicht erfüllt wird, kann eine gesammelte Signatur später für eine andere Anfrage wiederverwendet werden – das ist ein klassischer Replay-Angriff. Die Verknüpfung mit der Aktion verhindert außerdem, dass eine für eine harmlose Operation gesammelte Signatur auf eine gefährliche Aktion umgeleitet wird.

iOS: Ein Secure Enclave-Schlüssel, der bei jeder Verwendung Face ID erfordert

In iOS wird der Schlüssel direkt im Secure Enclave erstellt und mit einem Zugriffskontrollobjekt versehen, das jedes Mal eine Biometrieüberprüfung erfordert, wenn der Schlüssel verwendet wird. Im untenstehenden Swift-Code sind drei Optionen zu erkennen. kSecAttrAccessibleWhenUnlockedThisDeviceOnly verhindert, dass der Schlüssel in Backups oder andere Geräte übertragen wird. Die Flags .privateKeyUsage und .biometryCurrentSet erfordern eine Biometriebestätigung für das Signieren und verknüpfen den Schlüssel mit den aktuell registrierten Gesichtern oder Fingern. kSecAttrTokenIDSecureEnclave sorgt dafür, dass der Schlüssel im Hardware-Bereich gespeichert wird; das Secure Enclave unterstützt nur 256-Bit-Eliptikkurvenschlüssel (P-256), weshalb Typ und Größe des Schlüssels so festgelegt sind.

// 1. Create access control requiring Face ID / Touch ID for every use
var error: Unmanaged<CFError>?
guard let accessControl = SecAccessControlCreateWithFlags(
    kCFAllocatorDefault,
    kSecAttrAccessibleWhenUnlockedThisDeviceOnly,
    [.privateKeyUsage, .biometryCurrentSet],
    &error
) else { return }
// 2. Generate the key pair in the Secure Enclave
let attributes: [String: Any] = [
    kSecAttrKeyType as String: kSecAttrKeyTypeECSECPrimeRandom,
    kSecAttrKeySizeInBits as String: 256,
    kSecAttrTokenID as String: kSecAttrTokenIDSecureEnclave,
    kSecPrivateKeyAttrs as String: [
        kSecAttrIsPermanent as String: true,
        kSecAttrApplicationTag as String: "com.example.keys.transfer",
        kSecAttrAccessControl as String: accessControl
    ]
]
guard let privateKey = SecKeyCreateRandomKey(attributes as CFDictionary, &error) else { return }

Eine praktische Folge von .biometryCurrentSet ist, dass das Eintragen eines neuen Fingerspürabdrucks oder das Zurücksetzen von Face ID die Schlüssel ungültig macht. Das ist in der Regel gewünscht, wenn es um Zahlungen geht, bedeutet aber, dass Ihre App mit einem fehlenden Schlüssel angemessen umgehen und den Benutzer zur erneuten Registrierung leiten muss.

Laden Sie den öffentlichen Schlüssel nachdem der Benutzer sich normal angemeldet hat hoch. Später, wenn die Backend-Plattform eine zufällige Herausforderung für einen Übertrag vornimmt, signieren Sie diese mit dem privaten Schlüssel. Sie müssen keinen eigenen Hinweis anzeigen: Aufgrund der Zugriffskontroll-Flags wird der Signieraufruf automatisch Face ID oder Touch ID auslösen.

let algorithm: SecKeyAlgorithm = .ecdsaSignatureMessageX962SHA256
var signError: Unmanaged<CFError>?
// 3. This call automatically triggers the Face ID prompt because of the accessControl flags
guard let signature = SecKeyCreateSignature(
    privateKey,
    algorithm,
    challengeData as CFData,
    &signError
) else { return }
api.approve(challengeId, signature)

Falls der Benutzer den Vorgang abbricht oder die Scannung fehlschlägt, gibt SecKeyCreateSignature nil zurück und es existiert keine Signatur zum Senden, sodass es kein Erfolgsflag gibt, das ein Angreifer manipulieren könnte.

Android: Ein Keystore-Schlüssel, der über BiometricPrompt entsperrt wird

Der untenstehende Kotlin-Code erstellt einen ausschließlich zum Signieren verwendbaren EC-Schlüssel im AndroidKeyStore-Provider. setUserAuthenticationRequired(true) macht die Authentifizierung zwingend erforderlich, und setUserAuthenticationParameters(0, AUTH_BIOMETRIC_STRONG) setzt das Gültigkeitsfenster auf null Sekunden – das bedeutet, dass bei jeder Nutzung eine neue, starke biometrische Überprüfung stattfinden muss, anstatt einer Frist nach dem letzten Entsperrvorgang.

val spec = KeyGenParameterSpec.Builder(
    "transfer-key",
    KeyProperties.PURPOSE_SIGN
).setDigests(KeyProperties.DIGEST_SHA256)
    .setUserAuthenticationRequired(true)
    .setUserAuthenticationParameters(
        0,
        KeyProperties.AUTH_BIOMETRIC_STRONG
    ).build()
val generator = KeyPairGenerator.getInstance(
    KeyProperties.KEY_ALGORITHM_EC,
    "AndroidKeyStore"
)
generator.initialize(spec)
val publicKey = generator.generateKeyPair().public.encoded

Senden Sie die kodierte publicKey nach dem normalen Anmelden des Benutzers an den Backend-Server und speichern Sie sie zusammen mit dem Benutzer- sowie Geräteprofil. Wenn der Server später eine Herausforderung für einen Transfer aussendet, initialisieren Sie ein Signature-Objekt, packen es in ein CryptoObject und übergeben dieses an die Anfrage. Erst innerhalb von onAuthenticationSucceeded geben Sie die Herausforderungsdaten ein und erzeugen die Signatur.

val signature = Signature.getInstance("SHA256withECDSA")
signature.initSign(privateKey)
val crypto = BiometricPrompt.CryptoObject(signature)
prompt.authenticate(promptInfo, crypto)
override fun onAuthenticationSucceeded(result: AuthenticationResult) {
    val signed = result.cryptoObject!!.signature!!
        .apply { update(challenge) }.sign()
    api.approve(challengeId, signed)
}

Das Dialogfeld ist nicht die Sicherheitsgrenze – der CryptoObject ist es. Der Schlüsselspeicher weigert sich, die Signieroperation durchzuführen, es sei denn, die damit verbundene biometrische Überprüfung war erfolgreich, und das eigentliche Schlüsselmaterial bleibt im geschützten Speicher. Ihre Anwendung enthält lediglich die resultierende Signatur.

Auf dem Server prüfen Sie diese Signatur mit der registrierten öffentlichen Schlüssel. Falls sie zu einer noch nicht abgelaufenen, ungenutzten Herausforderung passt, genehmigen Sie die Übertragung oder stellen Sie ein kurzlebiges Token bereit, das auf diese Aktion beschränkt ist.

Wo Authentifizierungs-Token weiterhin hingehören

Die Überprüfung einer durch Hardware unterstützten Signatur beseitigt die Tokens nicht. Nach der Überprüfung ist es völlig angemessen, ein reguläres Zugriffstoken auszustellen, da Tokens weiterhin die praktische Methode zur Autorisierung des größten Teils des API-Traffics darstellen. Wenn Sie die Token-Logik im System entwerfen, gelten auch hier die Abwägungen aus unserem Leitfaden zur Refresh-Token-Strategie.

Speichern Sie diese Tokens in plattformgeschützten Speicherbereichen: dem Keychain auf iOS sowie dem von Keystore unterstützten Speicher auf Android. Lang lebende Refresh-Tokens sollten niemals in einfachen Einstellungen, gewöhnlichen Dateien oder für JavaScript zugänglichem Speicher abgelegt werden – was insbesondere in React Native-Apps wichtig ist, wo AsyncStorage standardmäßig verwendet wird, aber unverschlüsselt ist.

Dann stellt sich die Frage des Designs: Wie oft soll eine neue Hardware-Signatur angefordert werden?

  • Jeder API-Aufruf: fast immer zu langsam und äußerst nervig.
  • Jeder App-Start: eine sinnvolle Wahl für ein privates App-Sperrsystem.
  • Zur Bezahlung, Profilanpassung, Datenexport oder zur Freigabe eines neuen Geräts: häufig der optimale Zeitpunkt.
  • Jeder Einsatz eines Refresh-Tokens: sinnvoll für Konten mit höherem Risiko, vorausgesetzt die Benutzererfahrung kann die Anfragen bewältigen.

Betrachten Sie die Signatur als die erweiterte Authentifizierung und das Token als die kurzfristige Berechtigung, die daraus resultiert.

Beschränkungen von hardwarebasierten Schlüsseln

Dieser Ansatz ist stark, aber er ist kein Allheilmittel:

  • Er hilft nicht gegen einen legitimen Benutzer, der sein eigenes Telefon entsperrt und unter Druck beispielsweise eine schädliche Aktion genehmigt.
  • Es macht ein gerootetes oder jailbroken Gerät nicht vertrauenswürdiger; es erschwert lediglich das Extrahieren und Klonen der Schlüssel.
  • Es ersetzt die Serverseitige Betrugserkennung, das Rate Limiting oder die Anomalieüberwachung nicht.
  • Es beseitigt den Bedarf an Kontoverifizierungen nicht, da Menschen ihre Telefone verlieren und die Biometriedaten erneut einreichen müssen.
  • Es beweist die Kontrolle über einen registrierten Schlüssel nach lokaler Freigabe, nicht die tatsächliche Identität einer Person.
  • Planen Sie den Wiederherstellungsweg von Anfang an und gestalten Sie ihn absichtlich langsamer sowie strenger überprüfend als den üblichen Weg. Wenn eine Geräte-Schlüssel verschwindet, das Sperrbildschirm zurückgesetzt wird oder sich die Biometrie-Einrichtung ändert, sollte Ihre App bereit sein, einen neuen Schlüssel zu registrieren, und Ihr Server den alten widerrufen. In den Android-Dokumentationen heißt es, dass auf Authentifizierung angewiesene Schlüssel dauerhaft ungültig gemacht werden können, wenn sich der sichere Sperrbildschirm ändert oder die Biometrie-Einrichtung verändert – je nachdem, wie der Schlüssel konfiguriert wurde (KeyProtection.Builder-Dokumentation).

    Wie Passwörter zu diesem Design passen

    Passwörter basieren auf derselben Grundlage: einem öffentlichen/privaten Schlüsselpaar sowie einer vom Server gestellten Herausforderung, die mit dem privaten Schlüssel signiert wird. Für das Anmelden auf Webseiten und Konten sind sie in der Regel die beste Lösung, da das Betriebssystem und die Plattform sich um den größten Teil der komplexen Aufgaben kümmern. Passwörter sind ein standardisiertes, plattformübergreifendes Protokoll, das auf diesem Prinzip der hardwaregestützten Signatur beruht. Eine Besonderheit: Viele Passwörter werden über den Credentials-Manager der Plattform auf den Geräten des Benutzers synchronisiert, sodass sie nicht immer wie eine nicht exportierbare Keystore- oder Secure Enclave-Schlüsselstruktur an ein einzelnes Telefon gebunden sind.

    Diese Unterscheidung deutet auf eine einfache Trennung hin. Wählen Sie einen hardwareunterstützten Anwendungs-Schlüssel, wenn eine native Anwendung für eine bestimmte Aktion einen gerätespezifischen Nachweis benötigt. Wählen Sie Passkeys für ein modernes, passwortfreies Anmelden, wo immer Ihr Produkt sie unterstützen kann. In jedem Fall bleibt die Aufgabe des Servers dieselbe: Eine Signatur mit einem öffentlichen Schlüssel überprüfen, dem er bereits vertraut.

    Die richtige Werkzeugwahl für jeden Bedarf

    • Schutz von Daten in Transit: HTTPS.
    • Aufrechterhaltung des Anmeldenzustands des Benutzers: ein kurzlebiger Zugriffstoken zusammen mit einem geschützten Erneuerungstoken.
    • Sperre von privatem Inhalt beim Öffnen der Anwendung: Face ID, Touch ID oder BiometricPrompt.
    • Genehmigung einer Zahlung oder anderer hochriskanter Aktionen: eine durch Biometrie gesicherte hardwarebasierte Signatur.
    • Passwortfreies Anmelden: Passkeys.
    • Verringerung des Risikos einer TLS-Abfangung: Certificate Pinning.
  • Den Payload selbst vor dem eigenen Server geheim halten: Ende-zu-Ende-Verschlüsselung des Payloads.
  • Hauptpunkte

    Face ID- und Fingerabdruckscans authentifizieren keine Backend-Anfragen. Sie autorisieren lediglich die Verwendung eines Schlüssels; sicheres Hardware wird diesen Schlüssel verwendet, um eine neue Server-Herausforderung zu signieren; der Server überprüft anschließend die Signatur, bevor er entscheidet, was der Benutzer tun darf.

    • Biometrisch: lokale Genehmigung, für den Server unsichtbar.
    • Hardware-Schlüssel: Nachweis des Besitzes, der nicht aus dem Gerät kopiert werden kann.
    • Token: Die kurzfristige Genehmigung durch den Server.

    Halten Sie diese Rollen getrennt, binden Sie jede Herausforderung an ein Konto, einen Schlüssel und eine Aktion und planen Sie die Invalidation sowie Wiederherstellung von Schlüsseln. Das Ergebnis ist ein mobiler Authentifizierungsansatz, der leichter nachvollziehbar ist und erheblich schwieriger zu fälschen.