Los dispositivos compatibles que ejecutan Android 9 (nivel de API 28) o versiones posteriores te permiten usar la Confirmación de protección de Android. Cuando se usa este flujo de trabajo, tu app muestra un aviso al usuario en el que se le solicita aprobar una declaración corta. Esta declaración permite a la app ratificar que el usuario desea completar una transacción sensible, como un pago.
Si el usuario acepta la declaración, tu app podrá usar la clave de Android Keystore para firmar el mensaje que se mostró en el diálogo. La firma indica, con un alto grado de confianza, que el usuario vio la declaración y la aceptó.
Precaución: La Confirmación de protección de Android no proporciona un canal de información seguro para el usuario. Tu app no podrá prever ninguna garantía de confidencialidad más allá de las que ofrece la plataforma Android. En especial, no uses este flujo de trabajo para mostrar información sensible que no mostrarías normalmente en el dispositivo del usuario.
Una vez que el usuario confirme el mensaje, se asegurará su integridad, pero tu app aún deberá usar la encriptación de datos en tránsito para garantizar la confidencialidad del mensaje firmado.
Para admitir la confirmación de usuarios altamente confiables en tu app, completa estos pasos:
Genera una clave de firma asimétrica mediante la clase
KeyGenParameterSpec.Builder
. Cuando crees la clave, pasatrue
asetUserConfirmationRequired()
. Además, llama asetAttestationChallenge()
y pasa un valor de comprobación adecuado proporcionado por el usuario de confianza.Inscribe la nueva clave generada y la certificación de tu clave con el usuario de confianza adecuado.
Envía los detalles de la transacción a tu servidor y haz que genere y muestre un BLOB de datos adicionales. Estos datos pueden incluir información que aún se debe confirmar o sugerencias de análisis, como la configuración regional de la string de solicitud.
Para una implementación más segura, el BLOB debe contener un nonce criptográfico a fin de tener protección contra ataques de reproducción y desambiguar transacciones.
Configura el objeto
ConfirmationCallback
que informa a tu app una vez que el usuario acepte la solicitud mostrada en un diálogo de confirmación.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 // could respond to the prompt. } override fun onError(e: Exception?) { super.onError(e) // Handle the exception that the callback captured. } }
Si el usuario acepta el diálogo, se llama a la devolución de llamada
onConfirmed()
. El BLOBdataThatWasConfirmed
es una estructura de datos CBOR que contiene, entre otros detalles, el texto del mensaje que el usuario vio, así como los datos adicionales que pasó al compiladorConfirmationPrompt
. Tu app debe usar la clave creada anteriormente para firmar el BLOBdataThatWasConfirmed
. Luego, debes transferir este BLOB, junto con los detalles de la firma y de la transacción de vuelta al usuario de confianza.Para aprovechar por completo la garantía de seguridad que ofrece la Confirmación de protección de Android, el usuario de confianza debe llevar a cabo los siguientes pasos cuando reciba un mensaje firmado:
- Controla la firma en el mensaje, así como la cadena del certificado de atestación de la clave de firma.
- Controla que el certificado de atestación tenga configurado el indicador
TRUSTED_CONFIRMATION_REQUIRED
, que indique que la clave de firma requiere la confirmación de un usuario de confianza. Si la clave de firma es una clave RSA, comprueba que no tenga la propiedadPURPOSE_ENCRYPT
oPURPOSE_DECRYPT
. - Controla
extraData
para asegurarte de que este mensaje de confirmación pertenezca a una solicitud nueva y que no se haya procesado aún. Este paso protege contra ataques de reproducción. - Analiza
promptText
con el objetivo de obtener información sobre la acción o solicitud confirmada. Recuerda quepromptText
es la única parte del mensaje que el usuario realmente confirmó. El usuario de confianza jamás debe suponer que los datos por confirmar que se incluyen enextraData
corresponden apromptText
.
Agrega una lógica similar a la que se muestra en el siguiente fragmento de código para mostrar el diálogo mismo:
// This data structure varies by app type. This is just 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)
Recursos adicionales
Para obtener más información sobre la Confirmación de protección de Android, consulta los siguientes recursos.