Damit du die Absichten von Nutzern bestätigen kannst, wenn sie eine sensible Transaktion wie eine Zahlung initiieren, kannst du auf unterstützten Geräten mit Android 9 (API-Level 28) oder höher die Android geschützte Bestätigung verwenden. Wenn Sie diesen Workflow verwenden, wird in Ihrer App eine Aufforderung angezeigt, in der der Nutzer eine kurze Erklärung bestätigen muss, mit der er seine Absicht bekräftigt, die vertrauliche Transaktion abzuschließen.
Wenn der Nutzer die Erklärung akzeptiert, kann deine App einen Schlüssel aus dem Android-Schlüsselspeicher verwenden, um die im Dialogfeld angezeigte Nachricht zu signieren. Die Signatur zeigt mit sehr hoher Wahrscheinlichkeit, dass der Nutzer die Erklärung gesehen und ihr zugestimmt hat.
Achtung : Die Android geschützte Bestätigung bietet keinen sicheren Informationskanal für den Nutzer. Ihre App kann keine Vertraulichkeitsgarantien übernehmen, die über die von der Android-Plattform angebotenen hinausgehen. Verwende diesen Workflow insbesondere nicht, um vertrauliche Informationen anzuzeigen, die du normalerweise nicht auf dem Gerät des Nutzers anzeigen würdest.
Nachdem der Nutzer die Nachricht bestätigt hat, ist die Integrität der Nachricht gewährleistet. Ihre App muss jedoch weiterhin die Verschlüsselung von Daten bei der Übertragung verwenden, um die Vertraulichkeit der signierten Nachricht zu schützen.
Führe die folgenden Schritte aus, um die Nutzerbestätigung mit hoher Sicherheit in deiner App zu unterstützen:
Generieren Sie einen asymmetrischen Signaturschlüssel mit der Klasse
KeyGenParameterSpec.Builder. Übergeben Sie beim Erstellen des SchlüsselstrueansetUserConfirmationRequired(). Rufen Sie außerdemsetAttestationChallenge()auf und übergeben Sie einen geeigneten Challenge-Wert, der von der vertrauenden Partei bereitgestellt wird.Registriere den neu generierten Schlüssel und das Attestierungszertifikat deines Schlüssels bei der entsprechenden vertrauenden Partei.
Sende Transaktionsdetails an deinen Server und lass ihn ein großes binäres Datenobjekt (BLOB) mit zusätzlichen Daten generieren und zurückgeben. Zusätzliche Daten können die zu bestätigenden Daten oder Parsing-Hinweise enthalten, z. B. die Sprache des Prompt-Strings.
Für eine sicherere Implementierung muss das BLOB eine kryptografische Nonce enthalten, um vor Replay-Angriffen zu schützen und Transaktionen eindeutig zu machen.
Richte das Objekt
ConfirmationCallbackein, das deine App informiert, wenn der Nutzer die Aufforderung in einem Bestätigungsdialogfeld akzeptiert hat:Kotlin
class MyConfirmationCallback : ConfirmationCallback() { override fun onConfirmed(dataThatWasConfirmed: ByteArray?) { super.onConfirmed(dataThatWasConfirmed) // Sign dataThatWasConfirmed using your generated signing key. // By completing this process, you generate a signed statement. } override fun onDismissed() { super.onDismissed() // Handle case where user declined the prompt in the // confirmation dialog. } override fun onCanceled() { super.onCanceled() // Handle case where your app closed the dialog before the user // responded to the prompt. } override fun onError(e: Exception?) { super.onError(e) // Handle the exception that the callback captured. } }
Java
public class MyConfirmationCallback extends ConfirmationCallback { @Override public void onConfirmed(@NonNull byte[] dataThatWasConfirmed) { super.onConfirmed(dataThatWasConfirmed); // Sign dataThatWasConfirmed using your generated signing key. // By completing this process, you generate a signed statement. } @Override public void onDismissed() { super.onDismissed(); // Handle case where user declined the prompt in the // confirmation dialog. } @Override public void onCanceled() { super.onCanceled(); // Handle case where your app closed the dialog before the user // responded to the prompt. } @Override public void onError(Throwable e) { super.onError(e); // Handle the exception that the callback captured. } }
Wenn der Nutzer das Dialogfeld genehmigt, wird der Callback
onConfirmed()aufgerufen. DasdataThatWasConfirmed-BLOB ist eine CBOR-Datenstruktur, die unter anderem den Prompt-Text, den der Nutzer gesehen hat, sowie die zusätzlichen Daten enthält, die Sie an denConfirmationPrompt-Builder übergeben haben. Verwenden Sie den zuvor erstellten Schlüssel, um dasdataThatWasConfirmed-BLOB zu signieren, und geben Sie dieses BLOB zusammen mit der Signatur und den Transaktionsdetails an die vertrauende Seite zurück.Damit die von der Android geschützten Bestätigung gebotene Sicherheit voll ausgeschöpft werden kann, muss die vertrauende Partei nach Erhalt einer signierten Nachricht die folgenden Schritte ausführen:
- Prüfen Sie die Signatur der Nachricht sowie die Attestierungszertifikatskette des Signaturschlüssels.
- Prüfen Sie, ob das Attestierungszertifikat das Flag
TRUSTED_CONFIRMATION_REQUIREDenthält. Das Flag gibt an, dass für den Signaturschlüssel eine Bestätigung durch einen vertrauenswürdigen Nutzer erforderlich ist. Wenn der Signaturschlüssel ein RSA-Schlüssel ist, prüfen Sie, ob er das AttributPURPOSE_ENCRYPToderPURPOSE_DECRYPThat. - Prüfen Sie
extraData, um sicherzustellen, dass diese Bestätigungsnachricht zu einer neuen Anfrage gehört und noch nicht verarbeitet wurde. Dieser Schritt schützt vor Replay-Angriffen. - Parst die
promptText, um Informationen zur bestätigten Aktion oder Anfrage zu erhalten. Denken Sie daran, dass diepromptTextder einzige Teil der Nachricht ist, den der Nutzer tatsächlich bestätigt hat. Die vertrauende Seite darf niemals davon ausgehen, dass die zu bestätigenden Daten inextraDatamit dempromptTextübereinstimmen.
Fügen Sie Logik ähnlich der im folgenden Code-Snippet hinzu, um das Dialogfeld selbst anzuzeigen:
Kotlin
// This data structure varies by app type. This is an example. data class ConfirmationPromptData(val sender: String, val receiver: String, val amount: String) val myExtraData: ByteArray = byteArrayOf() val myDialogData = ConfirmationPromptData("Ashlyn", "Jordan", "$500") val threadReceivingCallback = Executor { runnable -> runnable.run() } val callback = MyConfirmationCallback() val dialog = ConfirmationPrompt.Builder(context) .setPromptText("${myDialogData.sender}, send ${myDialogData.amount} to ${myDialogData.receiver}?") .setExtraData(myExtraData) .build() dialog.presentPrompt(threadReceivingCallback, callback)
Java
// This data structure varies by app type. This is an example. class ConfirmationPromptData { String sender, receiver, amount; ConfirmationPromptData(String sender, String receiver, String amount) { this.sender = sender; this.receiver = receiver; this.amount = amount; } }; final int MY_EXTRA_DATA_LENGTH = 100; byte[] myExtraData = new byte[MY_EXTRA_DATA_LENGTH]; ConfirmationPromptData myDialogData = new ConfirmationPromptData("Ashlyn", "Jordan", "$500"); Executor threadReceivingCallback = Runnable::run; MyConfirmationCallback callback = new MyConfirmationCallback(); ConfirmationPrompt dialog = (new ConfirmationPrompt.Builder(getApplicationContext())) .setPromptText("${myDialogData.sender}, send ${myDialogData.amount} to ${myDialogData.receiver}?") .setExtraData(myExtraData) .build(); dialog.presentPrompt(threadReceivingCallback, callback);
Zusätzliche Ressourcen
Weitere Informationen zur Android geschützten Bestätigung findest du in den folgenden Ressourcen.
Blogs
- Android Protected Confirmation: Taking transaction security to the next level (Durch Android geschützte Bestätigung: Transaktionssicherheit auf einem ganz neuen Niveau)