Confirmation de protection Android

Pour vous aider à confirmer les intentions des utilisateurs lorsqu'ils initient une transaction sensible, par exemple quand ils effectuent un paiement, les appareils compatibles équipés d'Android 9 (niveau d'API 28) ou version ultérieure vous permettent d'utiliser Confirmation de protection Android. Lorsque vous utilisez ce workflow, votre application affiche une invite demandant à l'utilisateur d'approuver une courte déclaration qui réaffirme son intention d'effectuer la transaction sensible.

Si l'utilisateur accepte, votre application peut utiliser une clé d'Android Keystore pour signer le message affiché dans la boîte de dialogue. La signature indique, avec un degré de confiance très élevé, que l'utilisateur a vu la déclaration et l'a acceptée.

Attention : Confirmation de protection Android ne fournit pas de canal d'informations sécurisé à l'utilisateur. Votre application ne peut pas apporter d'autres garanties de confidentialité que celles offertes par la plate-forme Android. En particulier, n'utilisez pas ce workflow pour afficher des informations sensibles que vous n'afficheriez habituellement pas sur l'appareil de l'utilisateur.

Une fois le message confirmé par l'utilisateur, son intégrité est garantie. Toutefois, votre application doit continuer à utiliser le chiffrement des données en transit pour assurer la confidentialité du message signé.

Pour prendre en charge la confirmation de l'utilisateur avec un niveau d'assurance élevé dans votre application, procédez comme suit :

  1. Générez une clé de signature asymétrique à l'aide de la classe KeyGenParameterSpec.Builder. Lors de la création de la clé, transmettez true à setUserConfirmationRequired(). Appelez également setAttestationChallenge() en transmettant une valeur de défi appropriée fournie par le tiers de confiance.

  2. Enregistrez la clé nouvellement générée et le certificat d'attestation associé à votre clé auprès du tiers de confiance approprié.

  3. Envoyez les détails de la transaction à votre serveur, puis demandez-lui de générer et de renvoyer un objet binaire volumineux (BLOB) contenant des données supplémentaires. Les données supplémentaires peuvent inclure les données à confirmer ou les indications d'analyse, telles que les paramètres régionaux de la chaîne d'invite.

    Pour une mise en œuvre plus sécurisée, le BLOB doit contenir un nonce cryptographique pour offrir une protection contre les attaques par rejeu et faire la distinction entre les transactions.

  4. Configurez l'objet ConfirmationCallback qui informe votre application lorsque l'utilisateur a accepté l'invite affichée dans une boîte de dialogue de confirmation :

    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.
      }
    }
    

    Si l'utilisateur approuve la boîte de dialogue, le rappel onConfirmed() est appelé. Le BLOB dataThatWasConfirmed est une structure de données CBOR qui contient, entre autres, le texte d'invite que l'utilisateur a vu ainsi que les données supplémentaires que vous avez transmises dans le compilateur ConfirmationPrompt. Utilisez la clé créée précédemment pour signer le BLOB dataThatWasConfirmed, puis transmettez ce BLOB, ainsi que la signature et les détails de la transaction, au tiers de confiance.

    Pour exploiter pleinement l'assurance de sécurité proposée par Confirmation de protection Android, le tiers de confiance doit suivre les étapes ci-dessous lorsqu'il reçoit un message signé :

    1. Vérifier la signature sur le message ainsi que la chaîne de certificat d'attestation de la clé de signature.
    2. Vérifier que l'indicateur TRUSTED_CONFIRMATION_REQUIRED du certificat d'attestation est défini, ce qui signifie que la clé de signature nécessite une confirmation de l'utilisateur de confiance. Si la clé de signature est une clé RSA, vérifiez qu'elle ne possède pas la propriété PURPOSE_ENCRYPT ou PURPOSE_DECRYPT.
    3. Vérifier extraData pour s'assurer que ce message de confirmation appartient à une nouvelle requête et qu'il n'a pas encore été traité. Cette étape permet de lutter contre les attaques par rejeu.
    4. Analyser promptText pour obtenir des informations sur l'action ou la requête confirmée. N'oubliez pas que promptText est la seule partie du message que l'utilisateur a réellement confirmée. Le tiers de confiance ne doit jamais supposer que les données à confirmer incluses dans extraData correspondent au promptText.
  5. Ajoutez une logique semblable à celle présentée dans l'extrait de code suivant pour afficher la boîte de dialogue elle-même :

    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);
    

Ressources supplémentaires

Pour en savoir plus sur Confirmation de protection Android, consultez les ressources suivantes.

Articles de blog