Чтобы помочь вам подтвердить намерения пользователей при инициировании конфиденциальной транзакции, например, совершении платежа, поддерживаемые устройства под управлением Android 9 (уровень API 28) или выше позволяют использовать защищенное подтверждение Android. При использовании этого процесса ваше приложение отображает пользователю запрос на подтверждение короткого заявления, подтверждающего его намерение завершить конфиденциальную транзакцию.
Если пользователь принимает это утверждение, ваше приложение может использовать ключ из Android Keystore для подписи сообщения, отображаемого в диалоговом окне. Подпись с высокой степенью достоверности указывает на то, что пользователь ознакомился с утверждением и согласился с ним.
Внимание: функция «Защищенное подтверждение Android» не обеспечивает пользователю защищенный канал связи. Ваше приложение не может гарантировать конфиденциальность данных сверх тех гарантий, которые предоставляет платформа Android. В частности, не используйте этот алгоритм для отображения конфиденциальной информации, которую вы обычно не стали бы показывать на устройстве пользователя.
После подтверждения пользователем сообщения его целостность гарантируется, но ваше приложение всё равно должно использовать шифрование данных при передаче для защиты конфиденциальности подписанного сообщения.
Для обеспечения поддержки надежной аутентификации пользователей в вашем приложении выполните следующие шаги:
Сгенерируйте асимметричный ключ подписи, используя класс
KeyGenParameterSpec.Builder. При создании ключа передайтеtrueвsetUserConfirmationRequired(). Также вызовитеsetAttestationChallenge(), передав подходящее значение запроса, предоставленное проверяющей стороной.Зарегистрируйте сгенерированный ключ и сертификат подтверждения вашего ключа у соответствующей доверенной стороны.
Отправьте данные транзакции на свой сервер, чтобы он сгенерировал и вернул большой двоичный объект (BLOB) с дополнительными данными . Дополнительные данные могут включать в себя данные, подлежащие подтверждению, или подсказки для анализа, такие как локаль строки запроса.
Для более безопасной реализации BLOB-объект должен содержать криптографический одноразовый код для защиты от атак повторного воспроизведения и для уточнения транзакций.
Создайте объект
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, получающая сообщение сторона должна выполнить следующие действия после его получения:
- Проверьте подпись над сообщением, а также цепочку сертификатов подтверждения ключа подписи.
- Убедитесь, что в сертификате аттестации установлен флаг
TRUSTED_CONFIRMATION_REQUIRED, указывающий на то, что для ключа подписи требуется подтверждение доверенного пользователя. Если ключ подписи является ключом RSA, убедитесь, что у него нет свойствPURPOSE_ENCRYPTилиPURPOSE_DECRYPT. - Проверьте
extraData, чтобы убедиться, что это подтверждающее сообщение относится к новому запросу и еще не было обработано. Этот шаг защищает от атак повторного воспроизведения. - Проанализируйте текст
promptTextдля получения информации о подтвержденном действии или запросе. Помните, чтоpromptText— это единственная часть сообщения, которую пользователь фактически подтвердил. Получающая сторона ни в коем случае не должна предполагать, что данные, подлежащие подтверждению, включенные вextraDataсоответствуютpromptText.
Добавьте логику, аналогичную показанной в следующем фрагменте кода, чтобы отобразить само диалоговое окно:
Котлин
// 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 обратитесь к следующим ресурсам.