The Android Developer Challenge is back! Submit your idea before December 2.

Confirmación de protección de Android

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:

  1. Genera una clave de firma asimétrica con la clase KeyGenParameterSpec.Builder. Cuando crees la clave, pasa el elemento true a setUserConfirmationRequired(). Además, invoca a setAttestationChallenge() y transfiere un valor de comprobación adecuado que proporcione la parte de confianza.

  2. Inscribe la nueva clave generada y la certificación de tu clave con el usuario de confianza adecuado.

  3. 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 para tener protección contra ataques de reproducción y para desambiguar transacciones.

  4. Configura el objeto ConfirmationCallback, que informa a tu app cuando el usuario acepta la solicitud que se muestra 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 invoca a la devolución de llamada onConfirmed(). El BLOB dataThatWasConfirmed es una estructura de datos CBOR que contiene, entre otros detalles, el texto de la solicitud que vio el usuario y los datos adicionales que transferiste al generador ConfirmationPrompt. Tu app debe usar la clave creada anteriormente para firmar el BLOB dataThatWasConfirmed. 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:

    1. Controla la firma en el mensaje, así como la cadena del certificado de atestación de la clave de firma.
    2. 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 de tipo RSA, comprueba que no incluya la propiedad PURPOSE_ENCRYPT ni PURPOSE_DECRYPT.
    3. 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.
    4. Analiza el elemento promptText para obtener información sobre la acción o solicitud confirmada. Recuerda que promptText es la única parte del mensaje que el usuario realmente confirma. El usuario de confianza jamás debe suponer que los datos por confirmar que se incluyen en extraData corresponden a promptText.
  5. 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.

Blogs