Aby ułatwić potwierdzanie zamiarów użytkowników, gdy inicjują oni transakcję o charakterze wrażliwym, np. dokonując płatności, obsługiwane urządzenia z Androidem 9 (poziom interfejsu API 28) lub nowszym umożliwiają korzystanie z Bezpiecznego potwierdzenia Androida. Gdy używasz tego workflow, aplikacja wyświetla użytkownikowi prośbę o zatwierdzenie krótkiego oświadczenia, które potwierdza jego zamiar dokonania transakcji związanej z danymi wrażliwymi.
Jeśli użytkownik zaakceptuje oświadczenie, aplikacja może użyć klucza z Keystore Androida do podpisania wiadomości wyświetlanej w oknie dialogowym. Podpis z bardzo dużym prawdopodobieństwem wskazuje, że użytkownik zapoznał się z oświadczeniem i z nim zgodził.
Uwaga: Bezpieczne potwierdzenie na Androidzie nie zapewnia bezpiecznego kanału informacji dla użytkownika. Twoja aplikacja nie może zapewniać żadnych gwarancji poufności wykraczających poza te, które oferuje platforma Android. W szczególności nie używaj tego procesu do wyświetlania poufnych informacji, których nie wyświetlasz zwykle na urządzeniu użytkownika.
Po potwierdzeniu wiadomości przez użytkownika jej integralność jest zapewniona, ale aplikacja musi nadal szyfrować dane w transmisji, aby chronić poufność podpisanej wiadomości.
Aby zapewnić w aplikacji obsługę potwierdzenia tożsamości użytkownika o wysokim poziomie zabezpieczeń:
Wygeneruj klucz podpisywania asymetrycznego za pomocą klasy
KeyGenParameterSpec.Builder
. Podczas tworzenia klucza prześlij parametrtrue
do parametrusetUserConfirmationRequired()
. Ponadto wywołaj funkcjęsetAttestationChallenge()
, podając odpowiednią wartość odpowiedzi dostarczoną przez stronę pobierającą.Zarejestruj nowo wygenerowany klucz i certyfikat uwierzytelnienia klucza w odpowiedniej stronie ufającej.
Wyślij szczegóły transakcji na serwer, aby wygenerować i zwrócić duży obiekt binarny (BLOB) dodatkowych danych. Dane dodatkowe mogą zawierać dane do potwierdzenia lub wskazówki analizy, np. język ciągu tekstowego promptu.
Aby zapewnić bezpieczniejszą implementację, BLOB musi zawierać losowy ciąg znaków kryptograficznych (nonce) w celu ochrony przed atakami typu replay i rozróżniania transakcji.
Skonfiguruj obiekt
ConfirmationCallback
, który informuje aplikację, gdy użytkownik zaakceptuje prompt wyświetlany w oknie potwierdzenia: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. } }
Jeśli użytkownik zatwierdzi okno, wywoływana jest funkcja
onConfirmed()
. Obiekt BLOBdataThatWasConfirmed
to struktura danych w CBOR, która zawiera między innymi tekst promptu widoczny dla użytkownika, a także dodatkowe dane przekazane przez Ciebie do kreatoraConfirmationPrompt
. Użyj utworzonego wcześniej klucza, aby podpisać BLOBdataThatWasConfirmed
, a następnie prześlij ten BLOB wraz z podpisem i szczegółami transakcji do strony ufającej.Aby w pełni korzystać z zapewnionego przez Android Protected Confirmation poziomu bezpieczeństwa, po otrzymaniu podpisanej wiadomości użytkownik musi wykonać te czynności:
- Sprawdź podpis nad wiadomością oraz łańcuch certyfikatów poświadczenia klucza podpisywania.
- Sprawdź, czy certyfikat atesta ma ustawiony flagę
TRUSTED_CONFIRMATION_REQUIRED
, która wskazuje, że klucz podpisywania wymaga potwierdzenia przez zaufanego użytkownika. Jeśli klucz podpisywania to klucz RSA, sprawdź, czy nie ma właściwościPURPOSE_ENCRYPT
lubPURPOSE_DECRYPT
. - Sprawdź
extraData
, aby upewnić się, że ta wiadomość z potwierdzeniem dotyczy nowej prośby i nie została jeszcze przetworzona. Zapewnia to ochronę przed ponownymi atakami. - Przeanalizuj odpowiedź
promptText
, aby uzyskać informacje o potwierdzonym działaniu lub żądaniu. Pamiętaj, że polepromptText
to jedyny fragment wiadomości, który użytkownik potwierdził. Użytkownik nie może zakładać, że dane do potwierdzenia zawarte wextraData
odpowiadająpromptText
.
Aby wyświetlić sam dialog, dodaj logikę podobną do tej w następującym fragmencie kodu:
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);
Dodatkowe materiały
Więcej informacji o funkcji Potwierdzenie chronione na Androida znajdziesz w tych materiałach.