אפשר לאמת תעודות מזהות דיגיטליות בתהליכי אימות באפליקציה ובתהליכי אימות באתר. כדי לקבל אמצעי זיהוי מ-Google Wallet, צריך:
- מבצעים אינטגרציה באמצעות אפליקציה או אתר, בהתאם להוראות שמופיעות.
- כדי לבדוק את התהליך בסביבת הארגז של Google Wallet, צריך להשתמש בתעודה מזהה לבדיקה.
- כשמוכנים להפעיל את התכונה, ממלאים את הטופס הזה כדי לבקש אישור ולקבל את התנאים וההגבלות של קבלת אמצעי זיהוי מ-Google Wallet. עליך למלא את הטופס הזה עבור כל אחת מהישויות העסקיות שלך.
- בכל שאלה אפשר לפנות אל
wallet-identity-rp-support@google.com
.
דרישות מוקדמות
כדי לבדוק את הצגת תעודות הזהות באופן דיגיטלי, קודם צריך להירשם לתוכנית הבטא הציבורית באמצעות חשבון הבדיקה הרצוי (זה צריך להיות חשבון Gmail). לאחר מכן, מעבירים את הפרטים הבאים לאיש הקשר הייעודי שלכם ב-Google.
- קישור לתנאים ולהגבלות
- לוגו
- אתר
- מזהי חבילות אפליקציות (לשילובים של אפליקציות ל-Android)
- כולל גרסאות פיתוח או גרסאות לניפוי באגים
- חתימת האפליקציה
$ $ANDROID_SDK/build-tools/$BUILD_TOOLS_VERSION/apksigner verify --print-certs -v $APK
- מזהה Gmail ששימש להצטרפות לגרסת הבטא הפתוחה
פורמטים נתמכים של פרטי כניסה
קיימים כמה תקנים מוצעים שמגדירים את פורמט הנתונים של מסמכי זהות דיגיטלית, ושניים מהם זוכים לפופולריות רבה בתעשייה:
- mdocs – מוגדר על ידי ISO.
- פרטי כניסה ניתנים לאימות של W3C – מוגדרים על ידי W3C.
מנהל אמצעי התשלום ב-Android תומך בשני הפורמטים, אבל כרגע Google Wallet תומך רק בתעודות מזהות דיגיטליות מבוססות mdoc.
פרטי הכניסה הנתמכים
Google Wallet תומך ב-2 סוגים של פרטי כניסה:
- רישיון נהיגה בנייד (mDL)
- מסמכי זיהוי
אפשר לבקש את פרטי הכניסה האלה בתהליך שלכם באמצעות שינוי פרמטר אחד.
חוויית משתמש
בקטע הזה מתואר התהליך המומלץ להצגת מצגת באינטרנט. בתרשים הזרימה מוצג תהליך אימות הגיל באפליקציה למשלוח אלכוהול, אבל חוויית המשתמש דומה גם באתרים וגם בסוגים אחרים של תהליכי אימות.
![]() |
![]() |
![]() |
![]() |
![]() |
המשתמש מתבקש לאמת את הגיל באפליקציה או באתר | המשתמש רואה את פרטי הכניסה הזמינים שעומדים בדרישות | המשתמש רואה דף אישור ב-Google Wallet | המשתמש מאמת את עצמו כדי לאשר את השיתוף | הנתונים שנשלחו לאפליקציה או לאתר |
הערות חשובות
- לאפליקציה או לאתר יש גמישות באופן שבו הם יוצרים את נקודת הכניסה ל-API. כמו שמוצג בשלב 1, מומלץ להציג לחצן כללי כמו 'אימות באמצעות תעודה מזהה דיגיטלית', כי אנחנו צופים שעם הזמן יהיו אפשרויות נוספות מעבר ל-Google Wallet שיהיו זמינות דרך ה-API.
- מסך הבורר בשלב 2 מעובד על ידי Android. האישורים שעומדים בדרישות נקבעים לפי התאמה בין לוגיקת הרישום שסופקה על ידי כל ארנק לבין הבקשה שנשלחה על ידי הצד המסתמך
- שלב 3 מוצג על ידי Google Wallet. במסך הזה יופיעו השם, הלוגו ומדיניות הפרטיות שהמפתח סיפק ל-Google Wallet.
הוספת תהליך של תעודה מזהה דיגיטלית
אם למשתמש אין אמצעי זיהוי, מומלץ לספק קישור לצד הלחצן 'אימות באמצעות תעודה דיגיטלית'. הקישור יפנה את המשתמש ישירות אל Google Wallet כדי להוסיף תעודה דיגיטלית.
![]() |
![]() |
המשתמש מתבקש לאמת את הגיל באפליקציה או באתר | המשתמש מועבר אל Google Wallet כדי לקבל תעודה מזהה דיגיטלית |
אין תעודה מזהה דיגיטלית זמינה
אם המשתמש יבחר באפשרות 'אימות באמצעות תעודה מזהה דיגיטלית' בלי שתהיה לו תעודה מזהה דיגיטלית, תוצג לו הודעת השגיאה הזו.
![]() |
![]() |
המשתמש מתבקש לאמת את הגיל באפליקציה או באתר | אם למשתמש אין תעודה מזהה דיגיטלית, מוצגת לו שגיאה |
ממשק ה-API לא תומך בתכונה שמאפשרת ללמוד בשקט אם למשתמש יש תעודות מזהות דיגיטליות זמינות, כדי לשמור על פרטיות המשתמש. לכן מומלץ לכלול את האפשרות של קישור להצטרפות כמו שמוצג.
פורמט הבקשה לבקשת פרטי כניסה מזהים מהארנק
הנה דוגמה לבקשת mdoc requestJson
לקבלת פרטי זהות מכל ארנק במכשיר Android או באינטרנט.
{
"requests" : [
{
"protocol": "openid4vp",
"data": {<credential_request>} // This is an object, shouldn't be a string.
}
]
}
בקשת הצפנה
הפרמטר client_metadata
מכיל את המפתח הציבורי להצפנה של כל בקשה. תצטרכו לאחסן מפתחות פרטיים לכל בקשה ולהשתמש בהם כדי לאמת ולאשר את הטוקן שמתקבל מאפליקציית Wallet.
הפרמטר credential_request
ב-requestJson
יכלול את השדות הבאים.
{
"response_type": "vp_token",
"response_mode": "dc_api.jwt",
"nonce": "1234",
"dcql_query": {
"credentials": [
{
"id": "cred1",
"format": "mso_mdoc",
"meta": {
"doctype_value": "org.iso.18013.5.1.mDL" // this is for mDL. Use com.google.wallet.idcard.1 for ID pass
},
"claims": [
{
"path": [
"org.iso.18013.5.1",
"family_name"
]
},
{
"path": [
"org.iso.18013.5.1",
"given_name"
]
},
{
"path": [
"org.iso.18013.5.1",
"age_over_18"
]
}
]
}
]
},
"client_metadata": {
"jwks": {
"keys": [ // sample request encryption key
{
"kty": "EC",
"crv": "P-256",
"x": "pDe667JupOe9pXc8xQyf_H03jsQu24r5qXI25x_n1Zs",
"y": "w-g0OrRBN7WFLX3zsngfCWD3zfor5-NLHxJPmzsSvqQ",
"use": "enc",
"kid" : "1",
"alg" : "ECDH-ES",
}
]
},
"authorization_encrypted_response_alg": "ECDH-ES",
"authorization_encrypted_response_enc": "A128GCM"
}
}
אתם יכולים לבקש כל מספר של מאפיינים נתמכים מכל מסמך מזהה ששמור ב-Google Wallet.
באפליקציה
כדי לבקש פרטי כניסה לזהות מהאפליקציות שלכם ל-Android, פועלים לפי השלבים הבאים:
עדכון יחסי תלות
בקובץ build.gradle של הפרויקט, מעדכנים את יחסי התלות כדי להשתמש ב-Credential Manager (בטא):
dependencies {
implementation("androidx.credentials:credentials:1.5.0-beta01")
// optional - needed for credentials support from play services, for devices running Android 13 and below.
implementation("androidx.credentials:credentials-play-services-auth:1.5.0-beta01")
}
הגדרת הכלי לניהול פרטי כניסה
כדי להגדיר ולאתחל אובייקט CredentialManager
, מוסיפים לוגיקה דומה ללוגיקה הבאה:
// Use your app or activity context to instantiate a client instance of CredentialManager.
val credentialManager = CredentialManager.create(context)
מאפייני זהות בבקשה
במקום לציין פרמטרים נפרדים לבקשות אימות זהות, האפליקציה מספקת את כולם יחד כמחרוזת JSON בתוך CredentialOption. מנהל פרטי הכניסה מעביר את מחרוזת ה-JSON הזו לארנקים הדיגיטליים הזמינים בלי לבדוק את התוכן שלה. כל ארנק אחראי לפעולות הבאות: – ניתוח מחרוזת ה-JSON כדי להבין את בקשת הזהות. – קביעה אילו מפרטי הכניסה המאוחסנים שלה, אם יש כאלה, עומדים בדרישות הבקשה.
אנחנו ממליצים לשותפים ליצור את הבקשות שלהם בשרת, גם בשילובים של אפליקציות ל-Android.
תשתמשו ב-requestJson
מתוך Request Format
שכולל את request
בקריאה לפונקציה GetDigitalCredentialOption()
// The request in the JSON format to conform with
// the JSON-ified Digital Credentials API request definition.
val requestJson = generateRequestFromServer()
val digitalCredentialOption =
GetDigitalCredentialOption(requestJson = requestJson)
// Use the option from the previous step to build the `GetCredentialRequest`.
val getCredRequest = GetCredentialRequest(
listOf(digitalCredentialOption)
)
coroutineScope.launch {
try {
val result = credentialManager.getCredential(
context = activityContext,
request = getCredRequest
)
verifyResult(result)
} catch (e : GetCredentialException) {
handleFailure(e)
}
}
אימות התשובה
אחרי שמקבלים תשובה מהארנק, צריך לוודא שהתשובה היא credentialJson
.
// Handle the successfully returned credential.
fun verifyResult(result: GetCredentialResponse) {
val credential = result.credential
when (credential) {
is DigitalCredential -> {
val responseJson = credential.credentialJson
validateResponseOnServer(responseJson) // make a server call to validate the response
}
else -> {
// Catch any unrecognized credential type here.
Log.e(TAG, "Unexpected type of credential ${credential.type}")
}
}
}
// Handle failure.
fun handleFailure(e: GetCredentialException) {
when (e) {
is GetCredentialCancellationException -> {
// The user intentionally canceled the operation and chose not
// to share the credential.
}
is GetCredentialInterruptedException -> {
// Retry-able error. Consider retrying the call.
}
is NoCredentialException -> {
// No credential was available.
}
else -> Log.w(TAG, "Unexpected exception type ${e::class.java}")
}
}
התשובה של credentialJson
מכילה identityToken (JWT) מוצפן,
כפי שמוגדר על ידי W3C. אפליקציית Google Wallet אחראית ליצירת התגובה הזו.
דוגמה:
{
"protocol" : "openid4vp",
"data" : {
<encrpted_response>
}
}
תעבירו את התשובה הזו בחזרה לשרת כדי לאמת את האותנטיות שלה. כאן מוסבר איך לאמת את התגובה של פרטי הכניסה.
פיתוח אתרים
כדי לבקש פרטי זהות באמצעות Digital Credentials API ב-Chrome, צריך להירשם לגרסת המקור לניסיון של Digital Credentials API.
const credentialResponse = await navigator.credentials.get({
digital : {
requests : [
{
protocol: "openid4vp",
data: {<credential_request>} // This is an object, shouldn't be a string.
}
]
}
})
שולחים את התשובה מה-API הזה בחזרה לשרת כדי לאמת את התשובה של פרטי הכניסה
השלבים לאימות תשובת פרטי הכניסה
אחרי קבלת identityToken המוצפן מהאפליקציה או מהאתר, צריך לבצע כמה אימותים לפני שסומכים על התגובה.
פענוח התשובה באמצעות מפתח פרטי
השלב הראשון הוא לפענח את האסימון באמצעות המפתח הפרטי שנשמר ולקבל JSON של תשובה.
דוגמה ל-Python:
from jwcrypto import jwe, jwk # Retrieve the Private Key from Datastore reader_private_jwk = jwk.JWK.from_json(jwe_private_key_json_str) # Decrypt the JWE encrypted response from Google Wallet jwe_object = jwe.JWE() jwe_object.deserialize(encrypted_jwe_response_from_wallet) jwe_object.decrypt(reader_private_jwk) decrypted_payload_bytes = jwe_object.payload decrypted_data = json.loads(decrypted_payload_bytes)
הפלט של
decrypted_data
יהיה קובץ JSONvp_token
שמכיל את פרטי הכניסה.{ "vp_token": { "cred1": "<credential_token>" } }
יצירת תמליל של הסשן
השלב הבא הוא ליצור את SessionTranscript מתוך ISO/IEC 18013-5:2021 עם מבנה העברה ספציפי ל-Android או לאינטרנט:
SessionTranscript = [ null, // DeviceEngagementBytes not available null, // EReaderKeyBytes not available [ "OpenID4VPDCAPIHandover", AndroidHandoverDataBytes // BrowserHandoverDataBytes for Web ] ]
גם במעבר בין אפליקציות לאתרים ב-Android וגם במעבר בין אתרים, צריך להשתמש באותו ערך חד-פעמי שבו השתמשתם כדי ליצור את
credential_request
.העברה בין מכשירים ב-Android
AndroidHandoverData = [ origin, // "android:apk-key-hash:<base64SHA256_ofAppSigningCert>", clientId, // "android-origin:<app_package_name>", nonce, // nonce that was used to generate credential request ] AndroidHandoverDataBytes = hashlib.sha256(cbor2.dumps(AndroidHandoverData)).digest()
העברה של הדפדפן
BrowserHandoverData =[ origin, // Origin URL clientId, // "web-origin:<origin>" nonce, // nonce that was used to generate credential request ] BrowserHandoverDataBytes = hashlib.sha256(cbor2.dumps(BrowserHandoverData)).digest()
כשמשתמשים ב-
SessionTranscript
, צריך לאמת את DeviceResponse בהתאם לסעיף 9 בתקן ISO/IEC 18013-5:2021. התהליך הזה כולל כמה שלבים, כמו:בודקים את אישור המנפיק של המדינה. רשימת המנפיקים הנתמכים של אישורי IACA
אימות חתימת MSO (18013-5 Section 9.1.2)
חישוב ובדיקה של ValueDigests עבור רכיבי נתונים (18013-5 סעיף 9.1.2)
אימות החתימה של
deviceSignature
(18013-5 סעיף 9.1.3)
{
"version": "1.0",
"documents": [
{
"docType": "org.iso.18013.5.1.mDL",
"issuerSigned": {
"nameSpaces": {...}, // contains data elements
"issuerAuth": [...] // COSE_Sign1 w/ issuer PK, mso + sig
},
"deviceSigned": {
"nameSpaces": 24(<< {} >>), // empty
"deviceAuth": {
"deviceSignature": [...] // COSE_Sign1 w/ device signature
}
}
}
],
"status": 0
}
בדיקת הפתרון
כדי לבדוק את הפתרון, צריך ליצור ולהפעיל את מחזיק ההפניה בקוד הפתוח של אפליקציית Android. כך יוצרים ומריצים את אפליקציית מחזיק ההפניה:
- משכפלים את מאגר האפליקציות לדוגמה
- פותחים את הפרויקט ב-Android Studio.
- יוצרים את יעד
appholder
ומריצים אותו במכשיר Android או באמולטור.
אימות מבוסס-הוכחה באפס ידע (ZKP)
הוכחת אפס ידע (ZKP) היא שיטה קריפטוגרפית שמאפשרת לאדם (המוכיח) להוכיח למאמת שיש לו פיסת מידע מסוימת לזיהוי או שהוא עומד בקריטריון ספציפי (למשל, שהוא מעל גיל 18 או שיש לו אישור תקף) בלי לחשוף את הנתונים הבסיסיים בפועל. במילים אחרות, זו דרך לאמת הצהרה לגבי הזהות של אדם מסוים, תוך שמירה על הפרטיות של הפרטים הרגישים.
מערכות של זהויות דיגיטליות שמסתמכות על שיתוף ישיר של נתוני זהות לרוב דורשות מהמשתמשים לשתף מידע אישי מוגזם, מה שמגדיל את הסיכון לפריצות לנתונים ולגניבת זהות. הוכחות אפס ידע מציעות שינוי פרדיגמה, ומאפשרות אימות עם חשיפה מינימלית.
מושגים מרכזיים בנושא הוכחות אפס ידע (ZKP) בזהות דיגיטלית:
- המאמת: האדם שמנסה להוכיח היבט מסוים של הזהות שלו.
- מאמת: הישות שמבקשת הוכחה למאפיין זהות.
- ההוכחה: פרוטוקול קריפטוגרפי שמאפשר למוכיח לשכנע את המאמת שהטענה שלו נכונה בלי לחשוף את המידע הסודי.
מאפיינים מרכזיים של הוכחות אפס ידע:
- שלמות: אם הטענה נכונה וגם המוכיח וגם המאמת הם ישרים, המאמת ישתכנע.
- תקינות: אם הטענה שקרית, מוכיח לא ישר לא יכול (בהסתברות גבוהה מאוד) לשכנע מאמת ישר שהיא נכונה.
- ידע אפס: המאמת לא לומד שום דבר מעבר לעובדה שההצהרה נכונה. לא נחשפים נתונים בפועל מהזהות של המאמת.
כדי לקבל הוכחה של אפס ידע מ-Google Wallet, צריך לשנות את פורמט הבקשה ל-mso_mdoc_zk
ולהוסיף zk_system_type
לבקשה.
...
"dcql_query": {
"credentials": [{
"id": "cred1",
"format": "mso_mdoc_zk",
"meta": {
"doctype_value": "org.iso.18013.5.1.mDL"
"zk_system_type": [
{
"system": "longfellow-libzk-v1",
"circuit_hash": "bd3168ea0a9096b4f7b9b61d1c210dac1b7126a9ec40b8bc770d4d485efce4e9", // This will differ if you need more than 1 attribute.
"num_attributes": 1, // number of attributes (in claims) this has can support
"version": 3
}
],
"verifier_message": "challenge"
},
"claims": [{
...
"client_metadata": {
"jwks": {
"keys": [ // sample request encryption key
{
...
הארנק יחזיר לכם הוכחה מוצפנת של אפס ידע. אפשר לאמת את ההוכחה הזו מול אישורי IACA של מנפיקים באמצעות הספרייה longfellow-zk של Google.
לפרטים נוספים אפשר לפנות לתמיכה באימייל
wallet-identity-rp-support@google.com