Sử dụng bộ sưu tập để sắp xếp ngăn nắp các trang
Lưu và phân loại nội dung dựa trên lựa chọn ưu tiên của bạn.
Để giúp bạn xác nhận ý định của người dùng khi họ bắt đầu một giao dịch nhạy cảm, chẳng hạn như thanh toán, các thiết bị được hỗ trợ chạy Android 9 (API cấp 28) trở lên cho phép bạn sử dụng API Xác nhận bảo vệ của Android. Khi sử dụng quy trình này, ứng dụng của bạn sẽ hiển thị lời nhắc cho người dùng, yêu cầu họ phê duyệt một tuyên bố ngắn khẳng định lại ý định hoàn tất giao dịch nhạy cảm.
Nếu người dùng chấp nhận tuyên bố nói trên, thì ứng dụng của bạn có thể dùng một khoá trong Kho khoá Android để ký thông báo hiện trong hộp thoại. Với độ tin cậy rất cao, chữ ký này cho biết rằng người dùng đã xem và đồng ý với tuyên bố.
Thận trọng: API Xác nhận bảo vệ của Android không cung cấp kênh thông tin bảo mật cho người dùng. Ứng dụng của bạn không được đưa ra bất kỳ đảm bảo nào về tính bảo mật ngoài những đảm bảo mà nền tảng Android cung cấp. Cụ thể, không sử dụng quy trình này để hiển thị thông tin nhạy cảm mà bạn thường sẽ không hiển thị trên thiết bị của người dùng.
Sau khi người dùng xác nhận thông báo, tính toàn vẹn của thông báo sẽ được đảm bảo, nhưng ứng dụng của bạn vẫn phải dùng phương thức mã hoá dữ liệu trong khi truyền để bảo vệ tính bảo mật của thông báo đã ký này.
Để hỗ trợ người dùng xác nhận với độ đảm bảo cao trong ứng dụng của bạn, hãy hoàn tất các bước sau đây:
Đăng ký khoá mới tạo và chứng chỉ chứng thực của khoá với bên đáng tin cậy thích hợp.
Gửi thông tin giao dịch chi tiết đến máy chủ của bạn, đồng thời yêu cầu máy chủ tạo và trả về một đối tượng nhị phân có kích thước lớn (BLOB) của dữ liệu bổ sung. Dữ liệu bổ sung có thể bao gồm dữ liệu cần xác nhận hoặc gợi ý phân tích cú pháp, chẳng hạn như ngôn ngữ của chuỗi lời nhắc.
Nhằm giúp việc triển khai an toàn hơn, BLOB phải chứa một số mã hoá chỉ dùng một lần để chống lại các cuộc tấn công phát lại và để phân biệt các giao dịch.
Thiết lập đối tượng ConfirmationCallback để thông báo cho ứng dụng khi người dùng đã chấp nhận lời nhắc hiện trong hộp thoại xác nhận:
Kotlin
classMyConfirmationCallback:ConfirmationCallback(){overridefunonConfirmed(dataThatWasConfirmed:ByteArray?){super.onConfirmed(dataThatWasConfirmed)// Sign dataThatWasConfirmed using your generated signing key.// By completing this process, you generate a signed statement.}overridefunonDismissed(){super.onDismissed()// Handle case where user declined the prompt in the// confirmation dialog.}overridefunonCanceled(){super.onCanceled()// Handle case where your app closed the dialog before the user// responded to the prompt.}overridefunonError(e:Exception?){super.onError(e)// Handle the exception that the callback captured.}}
Java
publicclassMyConfirmationCallbackextendsConfirmationCallback{@OverridepublicvoidonConfirmed(@NonNullbyte[]dataThatWasConfirmed){super.onConfirmed(dataThatWasConfirmed);// Sign dataThatWasConfirmed using your generated signing key.// By completing this process, you generate a signed statement.}@OverridepublicvoidonDismissed(){super.onDismissed();// Handle case where user declined the prompt in the// confirmation dialog.}@OverridepublicvoidonCanceled(){super.onCanceled();// Handle case where your app closed the dialog before the user// responded to the prompt.}@OverridepublicvoidonError(Throwablee){super.onError(e);// Handle the exception that the callback captured.}}
Nếu người dùng phê duyệt hộp thoại này, thì lệnh gọi lại onConfirmed() sẽ được gọi. BLOB dataThatWasConfirmed là một cấu trúc dữ liệu CBOR chứa văn bản lời nhắc, cùng các thông tin chi tiết khác, mà người dùng nhìn thấy, cũng như dữ liệu bổ sung mà bạn đã truyền vào trình tạo ConfirmationPrompt. Hãy sử dụng khoá đã tạo trước đó để ký BLOB dataThatWasConfirmed rồi truyền BLOB này, cùng chữ ký và thông tin giao dịch, ngược trở lại cho bên đáng tin cậy.
Để tận dụng khả năng đảm bảo bảo mật mà API Xác nhận bảo vệ của Android cung cấp, bên đáng tin cậy phải thực hiện các bước sau đây khi nhận được một thông báo đã ký:
Kiểm tra chữ ký trên thông báo cũng như chuỗi chứng chỉ chứng thực của khoá ký.
Kiểm tra để đảm bảo chứng chỉ chứng thực đã đặt cờ TRUSTED_CONFIRMATION_REQUIRED nhằm chỉ ra rằng khoá ký yêu cầu người dùng đáng tin cậy xác nhận. Nếu khoá ký là một khoá RSA, hãy kiểm tra để chắc chắn rằng khoá đó không có thuộc tính PURPOSE_ENCRYPT hoặc PURPOSE_DECRYPT.
Hãy kiểm tra extraData để đảm bảo rằng thông báo xác nhận này thuộc về một yêu cầu mới và chưa được xử lý. Bước này giúp chống lại các cuộc tấn công phát lại.
Phân tích cú pháp promptText để biết thông tin về hành động hoặc yêu cầu đã xác nhận. Hãy nhớ rằng promptText là phần duy nhất của thông báo mà người dùng thực sự xác nhận. Bên tin cậy không bao giờ được giả định rằng dữ liệu cần xác nhận có trong extraData tương ứng với promptText.
Thêm logic tương tự như logic trong đoạn mã sau đây để hiển thị chính hộp thoại đó:
Kotlin
// This data structure varies by app type. This is an example.dataclassConfirmationPromptData(valsender:String,valreceiver:String,valamount:String)valmyExtraData:ByteArray=byteArrayOf()valmyDialogData=ConfirmationPromptData("Ashlyn","Jordan","$500")valthreadReceivingCallback=Executor{runnable->runnable.run()}valcallback=MyConfirmationCallback()valdialog=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.classConfirmationPromptData{Stringsender,receiver,amount;ConfirmationPromptData(Stringsender,Stringreceiver,Stringamount){this.sender=sender;this.receiver=receiver;this.amount=amount;}};finalintMY_EXTRA_DATA_LENGTH=100;byte[]myExtraData=newbyte[MY_EXTRA_DATA_LENGTH];ConfirmationPromptDatamyDialogData=newConfirmationPromptData("Ashlyn","Jordan","$500");ExecutorthreadReceivingCallback=Runnable::run;MyConfirmationCallbackcallback=newMyConfirmationCallback();ConfirmationPromptdialog=(newConfirmationPrompt.Builder(getApplicationContext())).setPromptText("${myDialogData.sender}, send ${myDialogData.amount} to ${myDialogData.receiver}?").setExtraData(myExtraData).build();dialog.presentPrompt(threadReceivingCallback,callback);
Tài nguyên khác
Để biết thêm thông tin về API Xác nhận bảo vệ của Android, hãy tham khảo các tài nguyên sau.
Nội dung và mã mẫu trên trang này phải tuân thủ các giấy phép như mô tả trong phần Giấy phép nội dung. Java và OpenJDK là nhãn hiệu hoặc nhãn hiệu đã đăng ký của Oracle và/hoặc đơn vị liên kết của Oracle.
Cập nhật lần gần đây nhất: 2023-12-14 UTC.
[null,null,["Cập nhật lần gần đây nhất: 2023-12-14 UTC."],[],[],null,["To help you confirm users' intentions when they initiate a sensitive\ntransaction, such as making a payment, supported devices that run Android 9 (API\nlevel 28) or higher let you use Android Protected Confirmation. When using this\nworkflow, your app displays a prompt to the user, asking them to approve a short\nstatement that reaffirms their intent to complete the sensitive transaction.\n\nIf the user accepts the statement, your app can use a key from Android Keystore\nto sign the message shown in the dialog. The signature indicates, with very high\nconfidence, that the user has seen the statement and has agreed to it. \n**Caution:**Android Protected Confirmation doesn't provide a\nsecure information channel for the user. Your app can't assume any\nconfidentiality guarantees beyond those that the Android platform offers. In\nparticular, don't use this workflow to display sensitive information that you\nwouldn't ordinarily show on the user's device.\n\nAfter the user confirms the message, the message's integrity is assured,\nbut your app must still use data-in-transit encryption to protect the\nconfidentiality of the signed message.\n\nTo provide support for high-assurance user confirmation in your app, complete\nthe following steps:\n\n1. [Generate an asymmetric signing key](/training/articles/keystore#GeneratingANewPrivateKey)\n using the\n [`KeyGenParameterSpec.Builder`](/reference/android/security/keystore/KeyGenParameterSpec.Builder)\n class. When creating the key, pass `true` into\n [`setUserConfirmationRequired()`](/reference/android/security/keystore/KeyGenParameterSpec.Builder#setUserConfirmationRequired(boolean)).\n Also, call [`setAttestationChallenge()`](/reference/android/security/keystore/KeyGenParameterSpec.Builder#setAttestationChallenge(byte%5B%5D)),\n passing a suitable challenge value provided by the relying party.\n\n2. Enroll the newly generated key and your key's attestation certificate with\n the appropriate relying party.\n\n3. Send transaction details to your server and have it generate and return a\n binary large object (BLOB) of *extra data*. Extra data might include the\n to-be-confirmed data or parsing hints, such as the locale of the prompt string.\n\n For a more secure implementation, the BLOB must contain a cryptographic\n nonce for protection against\n [replay attacks](https://www.pcmag.com/encyclopedia/term/50439/replay-attack)\n and to disambiguate transactions.\n | **Caution:** If the extra data field includes to-be-confirmed data, the relying party must verify the equivalent data that's sent with the prompt string. Android Protected Confirmation doesn't render the extra data, so your app can't assume that the user confirmed this data.\n4. Set up the\n [`ConfirmationCallback`](/reference/android/security/ConfirmationCallback)\n object that informs your app when the user has accepted the prompt shown in a\n confirmation dialog:\n\n Kotlin \n\n ```kotlin\n class MyConfirmationCallback : ConfirmationCallback() {\n\n override fun onConfirmed(dataThatWasConfirmed: ByteArray?) {\n super.onConfirmed(dataThatWasConfirmed)\n // Sign dataThatWasConfirmed using your generated signing key.\n // By completing this process, you generate a signed statement.\n }\n\n override fun onDismissed() {\n super.onDismissed()\n // Handle case where user declined the prompt in the\n // confirmation dialog.\n }\n\n override fun onCanceled() {\n super.onCanceled()\n // Handle case where your app closed the dialog before the user\n // responded to the prompt.\n }\n\n override fun onError(e: Exception?) {\n super.onError(e)\n // Handle the exception that the callback captured.\n }\n }\n ```\n\n Java \n\n ```java\n public class MyConfirmationCallback extends ConfirmationCallback {\n\n @Override\n public void onConfirmed(@NonNull byte[] dataThatWasConfirmed) {\n super.onConfirmed(dataThatWasConfirmed);\n // Sign dataThatWasConfirmed using your generated signing key.\n // By completing this process, you generate a signed statement.\n }\n\n @Override\n public void onDismissed() {\n super.onDismissed();\n // Handle case where user declined the prompt in the\n // confirmation dialog.\n }\n\n @Override\n public void onCanceled() {\n super.onCanceled();\n // Handle case where your app closed the dialog before the user\n // responded to the prompt.\n }\n\n @Override\n public void onError(Throwable e) {\n super.onError(e);\n // Handle the exception that the callback captured.\n }\n }\n ```\n\n If the user approves the dialog, the `onConfirmed()` callback is\n called. The `dataThatWasConfirmed` BLOB is a\n [CBOR data structure](http://cbor.io/) that contains,\n among other details, the prompt text that the user saw as well as the extra\n data that you passed into the\n [`ConfirmationPrompt`](/reference/android/security/ConfirmationPrompt)\n builder. Use the previously created key to sign the\n `dataThatWasConfirmed` BLOB, then pass this BLOB, along with the\n signature and transaction details, back to the relying party.\n | **Note:** Because the key was created using [`setUserConfirmationRequired()`](/reference/android/security/keystore/KeyGenParameterSpec.Builder#setUserConfirmationRequired(boolean)), it can only be used to sign data that's returned in the `dataThatWasConfirmed` parameter. Attempting to sign any other kind of data fails.\n\n To make full use of the security assurance that Android Protected\n Confirmation offers, the relying party must perform the following steps upon\n receiving a signed message:\n 1. Check the signature over the message as well as the attestation certificate chain of the signing key.\n 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`](/reference/android/security/keystore/KeyProperties#PURPOSE_ENCRYPT) or [`PURPOSE_DECRYPT`](/reference/android/security/keystore/KeyProperties#PURPOSE_DECRYPT) property.\n 3. Check `extraData` to make sure that this confirmation message belongs to a new request and hasn't been processed yet. This step protects against replay attacks.\n 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`.\n5. Add logic similar to that shown in the following code snippet to display the\n dialog itself:\n\n Kotlin \n\n ```kotlin\n // This data structure varies by app type. This is an example.\n data class ConfirmationPromptData(val sender: String,\n val receiver: String, val amount: String)\n\n val myExtraData: ByteArray = byteArrayOf()\n val myDialogData = ConfirmationPromptData(\"Ashlyn\", \"Jordan\", \"$500\")\n val threadReceivingCallback = Executor { runnable -\u003e runnable.run() }\n val callback = MyConfirmationCallback()\n\n val dialog = ConfirmationPrompt.Builder(context)\n .setPromptText(\"${myDialogData.sender}, send\n ${myDialogData.amount} to\n ${myDialogData.receiver}?\")\n .setExtraData(myExtraData)\n .build()\n dialog.presentPrompt(threadReceivingCallback, callback)\n ```\n\n Java \n\n ```java\n // This data structure varies by app type. This is an example.\n class ConfirmationPromptData {\n String sender, receiver, amount;\n ConfirmationPromptData(String sender, String receiver, String amount) {\n this.sender = sender;\n this.receiver = receiver;\n this.amount = amount;\n }\n };\n final int MY_EXTRA_DATA_LENGTH = 100;\n byte[] myExtraData = new byte[MY_EXTRA_DATA_LENGTH];\n ConfirmationPromptData myDialogData = new ConfirmationPromptData(\"Ashlyn\", \"Jordan\", \"$500\");\n Executor threadReceivingCallback = Runnable::run;\n MyConfirmationCallback callback = new MyConfirmationCallback();\n ConfirmationPrompt dialog = (new ConfirmationPrompt.Builder(getApplicationContext()))\n .setPromptText(\"${myDialogData.sender}, send ${myDialogData.amount} to ${myDialogData.receiver}?\")\n .setExtraData(myExtraData)\n .build();\n dialog.presentPrompt(threadReceivingCallback, callback);\n ```\n | **Note:** The confirmation prompt UI, which consists of a full-screen dialog, isn't customizable. However, the framework takes care of localizing button text for you.\n\nAdditional resources\n\nFor more information about Android Protected Confirmation, consult the following\nresources.\n\nBlogs\n\n- [Android Protected Confirmation: Taking transaction security to the next\n level](https://android-developers.googleblog.com/2018/10/android-protected-confirmation.html)"]]