Per aiutarti a confermare le intenzioni degli utenti quando avviano una transazione sensibile, ad esempio un pagamento, i dispositivi supportati che eseguono 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 messaggio 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 visualizzato nella finestra di dialogo. La firma indica, con un'affidabilità molto elevata, che l'utente ha visto la dichiarazione e l'ha accettata.
Attenzione: Android Protected Confirmation non fornisce un canale di informazioni sicuro per l'utente. La tua app non può presupporre 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 utente ad alta affidabilità nella tua app, completa i seguenti passaggi:
Genera una chiave di firma asimmetrica utilizzando la
KeyGenParameterSpec.Builderclasse. Quando crei la chiave, passatrueasetUserConfirmationRequired(). Inoltre, chiamasetAttestationChallenge(), passando un valore di challenge appropriato fornito dalla relying party.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 e fai in modo che generi e restituisca un oggetto binario di grandi dimensioni (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 messaggio.
Per un'implementazione più sicura, il BLOB deve contenere un nonce crittografico per la protezione dagli attacchi di replay e per disambiguare le transazioni.
Configura l'
ConfirmationCallbackoggetto che informa la tua app quando l'utente ha accettato il messaggio visualizzato in una finestra di dialogo di conferma: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. } }
Se l'utente approva la finestra di dialogo, viene chiamata la callback
onConfirmed(). Il BLOBdataThatWasConfirmedè una struttura di dati CBOR che contiene, tra gli altri dettagli, il testo del messaggio visualizzato dall'utente e i dati aggiuntivi che hai passato al builderConfirmationPrompt. Utilizza la chiave creata in precedenza per firmare il BLOBdataThatWasConfirmed, quindi passa questo BLOB, insieme alla firma e ai dettagli della transazione, alla relying party.Per sfruttare appieno la garanzia di sicurezza offerta dalla conferma protetta di Android, la relying party deve eseguire i seguenti passaggi dopo aver ricevuto un messaggio firmato:
- Controlla la firma del messaggio e la catena di certificati di attestazione della chiave di firma.
- Verifica che il certificato di attestazione abbia il flag
TRUSTED_CONFIRMATION_REQUIREDimpostato, il che indica che la chiave di firma richiede la conferma utente attendibile. Se la chiave di firma è una chiave RSA, verifica che non abbia laPURPOSE_ENCRYPToPURPOSE_DECRYPTproprietà. - Controlla
extraDataper assicurarti che questo messaggio di conferma appartenga a una nuova richiesta e non sia ancora stato elaborato. Questo passaggio protegge dagli attacchi di replay. - Analizza
promptTextper informazioni sull'azione o sulla richiesta confermata. Ricorda chepromptTextè l'unica parte del messaggio che l'utente ha effettivamente confermato. La relying party non deve mai presupporre che i dati da confermare inclusi inextraDatacorrispondano apromptText.
Aggiungi una logica simile a quella mostrata nel seguente snippet di codice per visualizzare la finestra di dialogo stessa:
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);
Risorse aggiuntive
Per saperne di più su Android Protected Confirmation, consulta le seguenti risorse.