כדי לעזור לכם לאשר את הכוונות של המשתמשים כשהם מתחילים עסקה רגישה, כמו ביצוע תשלום, מכשירים נתמכים עם Android 9 (רמת API 28) ומעלה מאפשרים לכם להשתמש באישור מאובטח של Android. כשמשתמשים בתהליך העבודה הזה, האפליקציה מציגה למשתמש בקשה לאשר הצהרה קצרה שמאשרת מחדש את הכוונה שלו להשלים את העסקה הרגישה.
אם המשתמש מאשר את ההצהרה, האפליקציה יכולה להשתמש במפתח מ-Android Keystore כדי לחתום על ההודעה שמוצגת בתיבת הדו-שיח. החתימה מציינת, ברמת ודאות גבוהה מאוד, שהמשתמש ראה את ההצהרה והסכים לה.
זהירות: האישור המאובטח של 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. } }
אם המשתמש מאשר את תיבת הדו-שיח, מתבצעת קריאה חוזרת (callback) של
onConfirmed(). ה-BLOB שלdataThatWasConfirmedהוא מבנה נתונים של CBOR שמכיל, בין היתר, את טקסט ההנחיה שהמשתמש ראה ואת הנתונים הנוספים שהעברתם ל-builder שלConfirmationPrompt. משתמשים במפתח שנוצר קודם כדי לחתום על ה-BLOB שלdataThatWasConfirmed, ואז מעבירים את ה-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, אפשר לעיין במקורות המידע הבאים.