Mantieni tutto organizzato con le raccolte
Salva e classifica i contenuti in base alle tue preferenze.
Per aiutarti a confermare le intenzioni degli utenti quando avviano una transazione sensibile, ad esempio un pagamento, i dispositivi supportati con Android 9 (livello API 28) o versioni successive ti consentono di utilizzare Android Protected Confirmation. Quando utilizzi questo
flusso di lavoro, la tua app mostra all'utente un prompt che gli chiede di approvare una breve
dichiarazione che riafferma la sua intenzione di completare la transazione sensibile.
Se l'utente accetta la dichiarazione, la tua app può utilizzare una chiave di Android Keystore
per firmare il messaggio mostrato nella finestra di dialogo. La firma indica, con un'affidabilità molto elevata, che l'utente ha letto la dichiarazione e l'ha accettata.
Attenzione: la conferma protetta di Android non fornisce un
canale di informazioni sicuro per l'utente. La tua app non può presumere alcuna
garanzia di riservatezza oltre a quelle offerte dalla piattaforma Android. In
particolare, non utilizzare questo flusso di lavoro per visualizzare informazioni sensibili che
normalmente non mostreresti sul dispositivo dell'utente.
Dopo che l'utente ha confermato il messaggio, l'integrità del messaggio è garantita,
ma la tua app deve comunque utilizzare la crittografia dei dati in transito per proteggere
la riservatezza del messaggio firmato.
Per fornire il supporto per la conferma dell'utente con garanzia elevata nella tua app, completa
i seguenti passaggi:
Registra la chiave appena generata e il certificato di attestazione della chiave con
la relying party appropriata.
Invia i dettagli della transazione al tuo server, che genererà e restituirà un
binary large object (BLOB) di dati aggiuntivi. I dati aggiuntivi potrebbero includere i dati da confermare o suggerimenti di analisi, ad esempio le impostazioni internazionali della stringa del prompt.
Per un'implementazione più sicura, il BLOB deve contenere un nonce crittografico per la protezione dagli attacchi di replay e per distinguere le transazioni.
Configura l'oggetto
ConfirmationCallback
che informa la tua app quando l'utente ha accettato il prompt mostrato in una
finestra di dialogo di conferma:
Kotlin
classMyConfirmationCallback:ConfirmationCallback(){overridefunonConfirmed(dataThatWasConfirmed:ByteArray?){super.onConfirmed(dataThatWasConfirmed)// Sign dataThatWasConfirmed using your generated signing key.// By completing this process, you generate a signed statement.}overridefunonDismissed(){super.onDismissed()// Handle case where user declined the prompt in the// confirmation dialog.}overridefunonCanceled(){super.onCanceled()// Handle case where your app closed the dialog before the user// responded to the prompt.}overridefunonError(e:Exception?){super.onError(e)// Handle the exception that the callback captured.}}
Java
publicclassMyConfirmationCallbackextendsConfirmationCallback{@OverridepublicvoidonConfirmed(@NonNullbyte[]dataThatWasConfirmed){super.onConfirmed(dataThatWasConfirmed);// Sign dataThatWasConfirmed using your generated signing key.// By completing this process, you generate a signed statement.}@OverridepublicvoidonDismissed(){super.onDismissed();// Handle case where user declined the prompt in the// confirmation dialog.}@OverridepublicvoidonCanceled(){super.onCanceled();// Handle case where your app closed the dialog before the user// responded to the prompt.}@OverridepublicvoidonError(Throwablee){super.onError(e);// Handle the exception that the callback captured.}}
Se l'utente approva la finestra di dialogo, viene chiamato il callback onConfirmed(). Il BLOB dataThatWasConfirmed è una
struttura di dati CBOR che contiene,
tra gli altri dettagli, il testo del prompt visualizzato dall'utente e i dati
aggiuntivi che hai passato al
generatore ConfirmationPrompt. Utilizza la chiave creata in precedenza per firmare il
BLOB dataThatWasConfirmed, quindi passa questo BLOB, insieme alla
firma e ai dettagli della transazione, alla relying party.
Per sfruttare appieno la garanzia di sicurezza offerta da Android Protected
Confirmation, la relying party deve eseguire i seguenti passaggi dopo
aver ricevuto un messaggio firmato:
Controlla la firma sul messaggio e la catena di certificati di attestazione della chiave di firma.
Verifica che il certificato di attestazione abbia il
flag TRUSTED_CONFIRMATION_REQUIRED impostato, il che indica che la chiave di firma
richiede la conferma dell'utente attendibile. Se la chiave di firma è una chiave RSA,
verifica che non abbia la proprietà
PURPOSE_ENCRYPT
o PURPOSE_DECRYPT.
Controlla extraData per assicurarti che questo messaggio di conferma appartenga a
una nuova richiesta e non sia ancora stato elaborato. Questo passaggio protegge
dagli attacchi di riproduzione.
Analizza promptText per informazioni sull'azione o sulla richiesta confermata. Ricorda che promptText è l'unica parte del messaggio che
l'utente ha effettivamente confermato. La relying party non deve mai presumere che i dati da
confermare inclusi in extraData corrispondano a promptText.
Aggiungi una logica simile a quella mostrata nello snippet di codice seguente per visualizzare la
finestra di dialogo stessa:
Kotlin
// This data structure varies by app type. This is an example.dataclassConfirmationPromptData(valsender:String,valreceiver:String,valamount:String)valmyExtraData:ByteArray=byteArrayOf()valmyDialogData=ConfirmationPromptData("Ashlyn","Jordan","$500")valthreadReceivingCallback=Executor{runnable->runnable.run()}valcallback=MyConfirmationCallback()valdialog=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.classConfirmationPromptData{Stringsender,receiver,amount;ConfirmationPromptData(Stringsender,Stringreceiver,Stringamount){this.sender=sender;this.receiver=receiver;this.amount=amount;}};finalintMY_EXTRA_DATA_LENGTH=100;byte[]myExtraData=newbyte[MY_EXTRA_DATA_LENGTH];ConfirmationPromptDatamyDialogData=newConfirmationPromptData("Ashlyn","Jordan","$500");ExecutorthreadReceivingCallback=Runnable::run;MyConfirmationCallbackcallback=newMyConfirmationCallback();ConfirmationPromptdialog=(newConfirmationPrompt.Builder(getApplicationContext())).setPromptText("${myDialogData.sender}, send ${myDialogData.amount} to ${myDialogData.receiver}?").setExtraData(myExtraData).build();dialog.presentPrompt(threadReceivingCallback,callback);
Risorse aggiuntive
Per saperne di più su Android Protected Confirmation, consulta le seguenti risorse.
I campioni di contenuti e codice in questa pagina sono soggetti alle licenze descritte nella Licenza per i contenuti. Java e OpenJDK sono marchi o marchi registrati di Oracle e/o delle sue società consociate.
Ultimo aggiornamento 2025-08-27 UTC.
[[["Facile da capire","easyToUnderstand","thumb-up"],["Il problema è stato risolto","solvedMyProblem","thumb-up"],["Altra","otherUp","thumb-up"]],[["Mancano le informazioni di cui ho bisogno","missingTheInformationINeed","thumb-down"],["Troppo complicato/troppi passaggi","tooComplicatedTooManySteps","thumb-down"],["Obsoleti","outOfDate","thumb-down"],["Problema di traduzione","translationIssue","thumb-down"],["Problema relativo a esempi/codice","samplesCodeIssue","thumb-down"],["Altra","otherDown","thumb-down"]],["Ultimo aggiornamento 2025-08-27 UTC."],[],[],null,["To help you confirm users' intentions when they initiate a sensitive\ntransaction, such as making a payment, supported devices that run Android 9 (API\nlevel 28) or higher let you use Android Protected Confirmation. When using this\nworkflow, your app displays a prompt to the user, asking them to approve a short\nstatement that reaffirms their intent to complete the sensitive transaction.\n\nIf the user accepts the statement, your app can use a key from Android Keystore\nto sign the message shown in the dialog. The signature indicates, with very high\nconfidence, that the user has seen the statement and has agreed to it. \n**Caution:**Android Protected Confirmation doesn't provide a\nsecure information channel for the user. Your app can't assume any\nconfidentiality guarantees beyond those that the Android platform offers. In\nparticular, don't use this workflow to display sensitive information that you\nwouldn't ordinarily show on the user's device.\n\nAfter the user confirms the message, the message's integrity is assured,\nbut your app must still use data-in-transit encryption to protect the\nconfidentiality of the signed message.\n\nTo provide support for high-assurance user confirmation in your app, complete\nthe following steps:\n\n1. [Generate an asymmetric signing key](/training/articles/keystore#GeneratingANewPrivateKey)\n using the\n [`KeyGenParameterSpec.Builder`](/reference/android/security/keystore/KeyGenParameterSpec.Builder)\n class. When creating the key, pass `true` into\n [`setUserConfirmationRequired()`](/reference/android/security/keystore/KeyGenParameterSpec.Builder#setUserConfirmationRequired(boolean)).\n Also, call [`setAttestationChallenge()`](/reference/android/security/keystore/KeyGenParameterSpec.Builder#setAttestationChallenge(byte%5B%5D)),\n passing a suitable challenge value provided by the relying party.\n\n2. Enroll the newly generated key and your key's attestation certificate with\n the appropriate relying party.\n\n3. Send transaction details to your server and have it generate and return a\n binary large object (BLOB) of *extra data*. Extra data might include the\n to-be-confirmed data or parsing hints, such as the locale of the prompt string.\n\n For a more secure implementation, the BLOB must contain a cryptographic\n nonce for protection against\n [replay attacks](https://www.pcmag.com/encyclopedia/term/50439/replay-attack)\n and to disambiguate transactions.\n | **Caution:** If the extra data field includes to-be-confirmed data, the relying party must verify the equivalent data that's sent with the prompt string. Android Protected Confirmation doesn't render the extra data, so your app can't assume that the user confirmed this data.\n4. Set up the\n [`ConfirmationCallback`](/reference/android/security/ConfirmationCallback)\n object that informs your app when the user has accepted the prompt shown in a\n confirmation dialog:\n\n Kotlin \n\n ```kotlin\n class MyConfirmationCallback : ConfirmationCallback() {\n\n override fun onConfirmed(dataThatWasConfirmed: ByteArray?) {\n super.onConfirmed(dataThatWasConfirmed)\n // Sign dataThatWasConfirmed using your generated signing key.\n // By completing this process, you generate a signed statement.\n }\n\n override fun onDismissed() {\n super.onDismissed()\n // Handle case where user declined the prompt in the\n // confirmation dialog.\n }\n\n override fun onCanceled() {\n super.onCanceled()\n // Handle case where your app closed the dialog before the user\n // responded to the prompt.\n }\n\n override fun onError(e: Exception?) {\n super.onError(e)\n // Handle the exception that the callback captured.\n }\n }\n ```\n\n Java \n\n ```java\n public class MyConfirmationCallback extends ConfirmationCallback {\n\n @Override\n public void onConfirmed(@NonNull byte[] dataThatWasConfirmed) {\n super.onConfirmed(dataThatWasConfirmed);\n // Sign dataThatWasConfirmed using your generated signing key.\n // By completing this process, you generate a signed statement.\n }\n\n @Override\n public void onDismissed() {\n super.onDismissed();\n // Handle case where user declined the prompt in the\n // confirmation dialog.\n }\n\n @Override\n public void onCanceled() {\n super.onCanceled();\n // Handle case where your app closed the dialog before the user\n // responded to the prompt.\n }\n\n @Override\n public void onError(Throwable e) {\n super.onError(e);\n // Handle the exception that the callback captured.\n }\n }\n ```\n\n If the user approves the dialog, the `onConfirmed()` callback is\n called. The `dataThatWasConfirmed` BLOB is a\n [CBOR data structure](http://cbor.io/) that contains,\n among other details, the prompt text that the user saw as well as the extra\n data that you passed into the\n [`ConfirmationPrompt`](/reference/android/security/ConfirmationPrompt)\n builder. Use the previously created key to sign the\n `dataThatWasConfirmed` BLOB, then pass this BLOB, along with the\n signature and transaction details, back to the relying party.\n | **Note:** Because the key was created using [`setUserConfirmationRequired()`](/reference/android/security/keystore/KeyGenParameterSpec.Builder#setUserConfirmationRequired(boolean)), it can only be used to sign data that's returned in the `dataThatWasConfirmed` parameter. Attempting to sign any other kind of data fails.\n\n To make full use of the security assurance that Android Protected\n Confirmation offers, the relying party must perform the following steps upon\n receiving a signed message:\n 1. Check the signature over the message as well as the attestation certificate chain of the signing key.\n 2. Check that the attestation certificate has the `TRUSTED_CONFIRMATION_REQUIRED` flag set, which indicates that the signing key requires trusted user confirmation. If the signing key is an RSA key, check that it doesn't have the [`PURPOSE_ENCRYPT`](/reference/android/security/keystore/KeyProperties#PURPOSE_ENCRYPT) or [`PURPOSE_DECRYPT`](/reference/android/security/keystore/KeyProperties#PURPOSE_DECRYPT) property.\n 3. Check `extraData` to make sure that this confirmation message belongs to a new request and hasn't been processed yet. This step protects against replay attacks.\n 4. Parse the `promptText` for information about the confirmed action or request. Remember that the `promptText` is the only part of the message that the user actually confirmed. The relying party must never assume that to-be confirmed data included in `extraData` corresponds to the `promptText`.\n5. Add logic similar to that shown in the following code snippet to display the\n dialog itself:\n\n Kotlin \n\n ```kotlin\n // This data structure varies by app type. This is an example.\n data class ConfirmationPromptData(val sender: String,\n val receiver: String, val amount: String)\n\n val myExtraData: ByteArray = byteArrayOf()\n val myDialogData = ConfirmationPromptData(\"Ashlyn\", \"Jordan\", \"$500\")\n val threadReceivingCallback = Executor { runnable -\u003e runnable.run() }\n val callback = MyConfirmationCallback()\n\n val dialog = ConfirmationPrompt.Builder(context)\n .setPromptText(\"${myDialogData.sender}, send\n ${myDialogData.amount} to\n ${myDialogData.receiver}?\")\n .setExtraData(myExtraData)\n .build()\n dialog.presentPrompt(threadReceivingCallback, callback)\n ```\n\n Java \n\n ```java\n // This data structure varies by app type. This is an example.\n class ConfirmationPromptData {\n String sender, receiver, amount;\n ConfirmationPromptData(String sender, String receiver, String amount) {\n this.sender = sender;\n this.receiver = receiver;\n this.amount = amount;\n }\n };\n final int MY_EXTRA_DATA_LENGTH = 100;\n byte[] myExtraData = new byte[MY_EXTRA_DATA_LENGTH];\n ConfirmationPromptData myDialogData = new ConfirmationPromptData(\"Ashlyn\", \"Jordan\", \"$500\");\n Executor threadReceivingCallback = Runnable::run;\n MyConfirmationCallback callback = new MyConfirmationCallback();\n ConfirmationPrompt dialog = (new ConfirmationPrompt.Builder(getApplicationContext()))\n .setPromptText(\"${myDialogData.sender}, send ${myDialogData.amount} to ${myDialogData.receiver}?\")\n .setExtraData(myExtraData)\n .build();\n dialog.presentPrompt(threadReceivingCallback, callback);\n ```\n | **Note:** The confirmation prompt UI, which consists of a full-screen dialog, isn't customizable. However, the framework takes care of localizing button text for you.\n\nAdditional resources\n\nFor more information about Android Protected Confirmation, consult the following\nresources.\n\nBlogs\n\n- [Android Protected Confirmation: Taking transaction security to the next\n level](https://android-developers.googleblog.com/2018/10/android-protected-confirmation.html)"]]