为帮助您在用户发起敏感交易(例如付款)时确认其意图,运行 Android 9 (API 级别 28) 或更高版本的受支持设备可让您使用 Android 受保护确认功能。使用此工作流程时,您的应用会向用户显示提示,要求他们批准一个简短的声明,以再次确认他们完成敏感交易的意图。
如果用户接受该声明,您的应用可以使用 Android 密钥库中的密钥对对话框中显示的消息进行签名。该签名以非常高的可信度表明用户已查看并同意该声明。
注意:Android 受保护确认不为用户提供安全的信息通道。您的应用不能假定超出 Android 平台所提供的任何机密性保证。特别是,不要使用此工作流程显示您通常不会在用户设备上显示的敏感信息。
用户确认消息后,消息的完整性得到保证,但您的应用仍必须使用传输中数据加密来保护已签名消息的机密性。
要在您的应用中提供对高可信度用户确认的支持,请完成以下步骤
使用
KeyGenParameterSpec.Builder
类生成非对称签名密钥。创建密钥时,将true
传递给setUserConfirmationRequired()
。此外,调用setAttestationChallenge()
,传递信赖方提供的合适质询值。向相应的信赖方注册新生成的密钥和密钥的证明证书。
将交易详情发送到您的服务器,让服务器生成并返回一个包含额外数据的二进制大对象 (BLOB)。额外数据可能包括待确认数据或解析提示,例如提示字符串的语言区域。
为了更安全的实现,BLOB 必须包含一个加密 nonce,以防止重放攻击并消除交易歧义。
设置
ConfirmationCallback
对象,该对象在用户接受确认对话框中显示的提示时通知您的应用。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. } }
如果用户批准对话框,则会调用
onConfirmed()
回调。dataThatWasConfirmed
BLOB 是一个 CBOR 数据结构,其中包含(除其他详细信息外)用户看到的提示文本以及您传递给ConfirmationPrompt
构建器的额外数据。使用先前创建的密钥对dataThatWasConfirmed
BLOB 进行签名,然后将此 BLOB 连同签名和交易详情传回信赖方。为充分利用 Android 受保护确认提供的安全保证,信赖方在收到签名消息后必须执行以下步骤
- 检查消息的签名以及签名密钥的证明证书链。
- 检查证明证书是否已设置
TRUSTED_CONFIRMATION_REQUIRED
标志,该标志表示签名密钥需要受信任的用户确认。如果签名密钥是 RSA 密钥,请检查它是否不具有PURPOSE_ENCRYPT
或PURPOSE_DECRYPT
属性。 - 检查
extraData
以确保此确认消息属于新的请求且尚未处理。此步骤可防范重放攻击。 - 解析
promptText
以获取有关已确认操作或请求的信息。请记住,promptText
是用户实际确认的消息的唯一部分。信赖方绝不能假定extraData
中包含的待确认数据与promptText
对应。
添加类似于以下代码片段中所示的逻辑,以显示对话框本身
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);
其他资源
有关 Android 受保护确认的更多信息,请查阅以下资源。