Подтверждение защиты Android

Чтобы помочь вам подтвердить намерения пользователей при инициировании конфиденциальной транзакции, например, совершении платежа, поддерживаемые устройства под управлением Android 9 (уровень API 28) или выше позволяют использовать защищенное подтверждение Android. При использовании этого процесса ваше приложение отображает пользователю запрос на подтверждение короткого заявления, подтверждающего его намерение завершить конфиденциальную транзакцию.

If the user accepts the statement, your app can use a key from Android Keystore to sign the message shown in the dialog. The signature indicates, with very high confidence, that the user has seen the statement and has agreed to it.

Caution: Android Protected Confirmation doesn't provide a secure information channel for the user. Your app can't assume any confidentiality guarantees beyond those that the Android platform offers. In particular, don't use this workflow to display sensitive information that you wouldn't ordinarily show on the user's device.

После подтверждения пользователем сообщения его целостность гарантируется, но ваше приложение всё равно должно использовать шифрование данных при передаче для защиты конфиденциальности подписанного сообщения.

Для обеспечения поддержки надежной аутентификации пользователей в вашем приложении выполните следующие шаги:

  1. Generate an asymmetric signing key using the KeyGenParameterSpec.Builder class. When creating the key, pass true into setUserConfirmationRequired() . Also, call setAttestationChallenge() , passing a suitable challenge value provided by the relying party.

  2. Зарегистрируйте сгенерированный ключ и сертификат подтверждения вашего ключа у соответствующей доверенной стороны.

  3. Send transaction details to your server and have it generate and return a binary large object (BLOB) of extra data . Extra data might include the to-be-confirmed data or parsing hints, such as the locale of the prompt string.

    Для более безопасной реализации BLOB-объект должен содержать криптографический одноразовый код для защиты от атак повторного воспроизведения и для уточнения транзакций.

  4. Создайте объект ConfirmationCallback , который будет сообщать вашему приложению, когда пользователь принял запрос, отображаемый в диалоговом окне подтверждения:

    Котлин

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

    Если пользователь одобряет диалог, вызывается функция обратного вызова onConfirmed() . BLOB-объект dataThatWasConfirmed представляет собой структуру данных CBOR , содержащую, помимо прочих деталей, текст запроса, который видел пользователь, а также дополнительные данные, переданные в конструктор ConfirmationPrompt . Используйте ранее созданный ключ для подписи BLOB-объекта dataThatWasConfirmed , затем передайте этот BLOB-объект вместе с подписью и данными транзакции обратно проверяющей стороне.

    Для того чтобы в полной мере воспользоваться преимуществами системы Android Protected Confirmation, получающая сообщение сторона должна выполнить следующие действия после его получения:

    1. Проверьте подпись над сообщением, а также цепочку сертификатов подтверждения ключа подписи.
    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 or PURPOSE_DECRYPT property.
    3. Проверьте extraData , чтобы убедиться, что это подтверждающее сообщение относится к новому запросу и еще не было обработано. Этот шаг защищает от атак повторного воспроизведения.
    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 .
  5. Добавьте логику, аналогичную показанной в следующем фрагменте кода, чтобы отобразить само диалоговое окно:

    Котлин

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

Дополнительные ресурсы

Для получения более подробной информации о защищенном подтверждении Android обратитесь к следующим ресурсам.

Блоги