כדי לעזור לכם לאשר את כוונות המשתמשים כשהם מתחילים עסקה רגישה, כמו ביצוע תשלום, במכשירים נתמכים עם Android מגרסה 9 (רמת API 28) ואילך, אפשר להשתמש באישור מוגן של Android. בתהליך העבודה הזה, באפליקציה מוצגת למשתמש בקשה לאשר הצהרה קצרה שמאשרת את הכוונה שלו להשלים את העסקה הרגישה.
אם המשתמש יאשר את ההצהרה, האפליקציה תוכל להשתמש במפתח מ-Android Keystore כדי לחתום על ההודעה שמוצגת בתיבת הדו-שיח. החתימה מציינת, ברמת ודאות גבוהה מאוד, שהמשתמש ראה את ההצהרה והסכים לה.
זהירות: האישור המוגן ב-Android לא מספק למשתמש ערוץ מידע מאובטח. האפליקציה שלך לא יכולה להניח שיש ערבויות סודיות מעבר לאלה שמציעה פלטפורמת Android. בפרט, אל תשתמשו בתהליך העבודה הזה כדי להציג מידע רגיש שבדרך כלל לא מוצג במכשיר של המשתמש.
אחרי שהמשתמש מאשר את ההודעה, מובטחת שלמות ההודעה, אבל האפליקציה עדיין צריכה להשתמש בהצפנת נתונים במעבר כדי להגן על הסודיות של ההודעה החתומה.
כדי לספק תמיכה באימות משתמש ברמת מהימנות גבוהה באפליקציה שלכם, צריך לבצע את השלבים הבאים:
יוצרים מפתח חתימה אסימטרי באמצעות המחלקה
KeyGenParameterSpec.Builder
. כשיוצרים את המפתח, מעבירים אתtrue
אלsetUserConfirmationRequired()
. בנוסף, צריך להתקשר אלsetAttestationChallenge()
ולהעביר ערך מתאים של אתגר שסופק על ידי הצד המסתמך.רושמים את המפתח החדש ואת אישור האימות של המפתח אצל הצד המסתמך המתאים.
שולחים את פרטי העסקה לשרת, והוא יוצר ומחזיר אובייקט בינארי גדול (BLOB) של נתונים נוספים. נתונים נוספים יכולים לכלול נתונים שצריך לאשר או רמזים לניתוח, כמו הלוקאל של מחרוזת ההנחיה.
כדי להטמיע את ה-BLOB בצורה מאובטחת יותר, הוא צריך להכיל ערך חד-פעמי מוצפן כדי להגן מפני מתקפות שידור חוזר וכדי להבחין בין עסקאות.
מגדירים את האובייקט
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()
. dataThatWasConfirmed
BLOB הוא מבנה נתונים של CBOR שמכיל, בין היתר, את טקסט ההנחיה שהמשתמש ראה וגם את הנתונים הנוספים שהעברתם לבונה שלConfirmationPrompt
. משתמשים במפתח שנוצר קודם כדי לחתום על ה-BLOBdataThatWasConfirmed
, ואז מעבירים את ה-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 זמין במקורות המידע הבאים.