Aby pomóc Ci potwierdzać intencje użytkowników podczas inicjowania poufnych transakcji, takich jak dokonywanie płatności, obsługiwane urządzenia z Androidem 9 (poziom API 28) lub nowszym umożliwiają korzystanie z zabezpieczonego potwierdzenia w Androidzie. W tym przypadku aplikacja wyświetla prośbę o zatwierdzenie krótkiego oświadczenia, które potwierdza zamiar użytkownika, aby dokończyć transakcję wymagającą większej ostrożności.
Jeśli użytkownik zaakceptuje oświadczenie, aplikacja może użyć klucza z Android Keystore do podpisania wiadomości wyświetlanej w oknie dialogowym. Podpis z bardzo wysokim poziomem ufności wskazuje, że użytkownik zapoznał się z oświadczeniem i wyraził na nie zgodę.
Ostrzeżenie: potwierdzenie chronione w Androidzie nie zapewnia użytkownikowi bezpiecznego kanału informacji. Aplikacja nie może zakładać żadnych gwarancji poufności poza tymi, które oferuje platforma Android. W szczególności nie używaj tego procesu do wyświetlania informacji poufnych, których zwykle nie pokazujesz na urządzeniu użytkownika.
Gdy użytkownik potwierdzi wiadomość, jej integralność jest zapewniona, ale aplikacja musi nadal używać szyfrowania danych w trakcie przesyłania, aby chronić poufność podpisanej wiadomości.
Aby w aplikacji obsługiwać potwierdzenie użytkownika o wysokim poziomie bezpieczeństwa, wykonaj te czynności:
Wygeneruj asymetryczny klucz podpisywania za pomocą klasy
KeyGenParameterSpec.Builder. Podczas tworzenia klucza przekażtruedosetUserConfirmationRequired(). Zadzwoń też pod numersetAttestationChallenge(), przekazując odpowiednią wartość weryfikacyjną podaną przez podmiot polegający na tożsamości.Zarejestruj nowo wygenerowany klucz i certyfikat poświadczenia klucza u odpowiedniej strony ufającej.
Wyślij szczegóły transakcji na serwer, aby wygenerował i zwrócił dodatkowe dane w postaci dużego obiektu binarnego (BLOB). Dodatkowe dane mogą obejmować dane do potwierdzenia lub wskazówki dotyczące analizowania, np. ustawienia regionalne ciągu promptu.
Aby zwiększyć bezpieczeństwo implementacji, obiekt BLOB musi zawierać kryptograficzny nonce, który chroni przed atakami typu replay i umożliwia rozróżnianie transakcji.
Skonfiguruj obiekt
ConfirmationCallbackinformujący aplikację, że użytkownik zaakceptował prośbę wyświetlaną 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, zostanie wywołane wywołanie zwrotne
onConfirmed().dataThatWasConfirmedBLOB to struktura danych CBOR, która zawiera m.in. tekst promptu wyświetlany użytkownikowi oraz dodatkowe dane przekazane do narzędzia do tworzeniaConfirmationPrompt. Użyj utworzonego wcześniej klucza do podpisaniadataThatWasConfirmedBLOB, a następnie przekaż ten BLOB wraz z podpisem i szczegółami transakcji z powrotem do podmiotu polegającego na tożsamości.Aby w pełni wykorzystać gwarancję bezpieczeństwa, jaką zapewnia funkcja Protected Confirmation na Androidzie, po otrzymaniu podpisanego komunikatu strona ufająca musi wykonać te czynności:
- Sprawdź podpis wiadomości oraz łańcuch certyfikatów atestu klucza podpisywania.
- Sprawdź, czy certyfikat atestu ma ustawioną flagę
TRUSTED_CONFIRMATION_REQUIRED, która wskazuje, że klucz podpisywania wymaga potwierdzenia przez zaufanego użytkownika. Jeśli klucz podpisywania jest kluczem RSA, sprawdź, czy nie ma właściwościPURPOSE_ENCRYPTaniPURPOSE_DECRYPT. - Sprawdź, czy
extraDatajest zaznaczone, aby upewnić się, że ten komunikat z potwierdzeniem dotyczy nowego żądania i nie został jeszcze przetworzony. Ten krok chroni przed atakami typu replay. - Przeanalizuj
promptText, aby uzyskać informacje o potwierdzonym działaniu lub żądaniu. Pamiętaj, żepromptTextto jedyna część wiadomości, którą użytkownik potwierdził. Strona ufająca nie może nigdy zakładać, że dane do potwierdzenia zawarte wextraDataodpowiadająpromptText.
Aby wyświetlić okno, dodaj logikę podobną do tej, która jest pokazana w tym 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 potwierdzeniu chronionym na Androidzie znajdziesz w tych materiałach.