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

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

Если пользователь принимает это заявление, ваше приложение может использовать ключ из хранилища ключей Android для подписи сообщения, отображаемого в диалоговом окне. Подпись с высокой степенью уверенности подтверждает, что пользователь ознакомился с заявлением и согласен с ним.

Внимание: Android Protected Confirmation не предоставляет пользователю безопасный канал передачи информации. Ваше приложение не может гарантировать конфиденциальность, превышающую гарантии, предоставляемые платформой Android. В частности, не используйте этот рабочий процесс для отображения конфиденциальной информации, которую вы обычно не отображаете на устройстве пользователя.

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

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

  1. Сгенерируйте асимметричный ключ подписи с помощью класса KeyGenParameterSpec.Builder . При создании ключа передайте true в setUserConfirmationRequired() . Также вызовите setAttestationChallenge() , передав соответствующее значение вызова, предоставленное проверяющей стороной.

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

  3. Отправьте данные о транзакции на свой сервер и дайте ему возможность сгенерировать и вернуть большой двоичный объект (BLOB) с дополнительными данными . Дополнительные данные могут включать данные, требующие подтверждения, или подсказки для анализа, например, локаль строки запроса.

    Для более безопасной реализации 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.
          }
      }

    Ява

    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. Убедитесь, что у сертификата подтверждения установлен флаг TRUSTED_CONFIRMATION_REQUIRED , указывающий на необходимость подтверждения ключа подписи доверенным пользователем. Если ключ подписи — это ключ RSA, проверьте, что у него нет свойств PURPOSE_ENCRYPT или PURPOSE_DECRYPT .
    3. Проверьте extraData , чтобы убедиться, что это подтверждающее сообщение относится к новому запросу и ещё не обработано. Этот шаг защищает от атак повторного воспроизведения.
    4. Проанализируйте promptText на предмет информации о подтверждённом действии или запросе. Помните, что promptText — это единственная часть сообщения, которую пользователь фактически подтвердил. Проверяющая сторона ни при каких обстоятельствах не должна предполагать, что данные, подлежащие подтверждению, включённые в extraData соответствуют 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)

    Ява

      // 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 можно найти в следующих ресурсах.

Блоги