ניתוח מעמיק של אימות משתמשים

במסמך הזה מוסבר על השימוש ב-userVerification ב-WebAuthn ועל התנהגויות הדפדפן שנובעות מכך שמציינים את userVerification בתהליך היצירה או האימות של מפתח הגישה.

מה זה 'אימות משתמש' ב-WebAuthn?

מפתחות גישה מבוססים על קריפטוגרפיה של מפתח ציבורי. כשיוצרים מפתח גישה, נוצר זוג מפתחות ציבורי-פרטי, המפתח הפרטי מאוחסן אצל ספק מפתחות הגישה והמפתח הציבורי מוחזר לשרת של הצד הנסמך (RP) לצורך אחסון. השרת יכול לאמת משתמשים על ידי אימות חתימה שחתומה על ידי אותו מפתח גישה באמצעות המפתח הציבורי המותאם. הסימון 'משתמש נוכחי' (UP) בפרטי הכניסה של מפתח ציבורי מוכיח שמישהו יצר אינטראקציה עם המכשיר במהלך האימות.

אימות משתמש הוא שכבת אבטחה אופציונלית שמטרתה לטעון שהאדם הנכון היה נוכח במהלך האימות, ולא רק על ידי אדם אחר, כפי שמצהירים נוכחות המשתמש. בסמארטפונים, בדרך כלל עושים זאת באמצעות מנגנון לנעילת מסך, בין אם מדובר במידע ביומטרי ובין אם בקוד אימות או בסיסמה. אם בוצע אימות משתמש, מדווח בסימון 'UV' שמוחזר בנתוני מאמת החשבונות במהלך הרישום של מפתח הגישה והאימות

צילום מסך של תיבת דו-שיח לאימות משתמש ב'צרור המפתחות של iCloud' ב-macOS. בתיבת הדו-שיח תוצג בקשה למשתמש להיכנס באמצעות Touch ID, והמקור שביקש אימות יוצג יחד עם שם המשתמש. בפינה השמאלית העליונה של תיבת הדו-שיח מופיע הלחצן 'ביטול'.
תיבת דו-שיח לאימות משתמשים ב-iCloud Keychain ב-macOS.
צילום מסך של תיבת דו-שיח לאימות משתמש ב-Chrome ל-Android. בתיבת הדו-שיח תוצג למשתמש בקשה לאמת את הזהות שלו באמצעות זיהוי פנים או זיהוי טביעת אצבע, ויוצג המקור שביקש אימות. בפינה הימנית התחתונה מופיעה האפשרות לבצע אימות באמצעות קוד אימות.
תיבת דו-שיח לאימות משתמש ב-Android Chrome.

כיצד מתבצע אימות של UP ו-UV בשרת

הסימונים הבוליאניים של נוכחות המשתמש (UP) והמאפיינים הבוליאניים (UV) מסומנים לשרת בשדה הנתונים של מאמת החשבונות. במהלך האימות, אפשר לאמת את התוכן בשדה הנתונים של מאמת החשבונות על ידי אימות החתימה באמצעות המפתח הציבורי ששמור. כל עוד החתימה חוקית, השרת יכול להחשיב שהחתימה היא אמיתית.

תיאור של מבנה הנתונים לאימות. משמאל לימין, כל קטע במבנה הנתונים כתוב 'RP ID HASH' (32 בייטים), 'FLAGS' (בייט אחד), 'COUNTER' (4 בייטים, uint32 גדול או גדול), 'ATTESTE CRED. DATA' (אורך משתנה אם קיים), ו-'ExtensionS' (אורך משתנה אם קיים (CBOR). הקטע 'FLAGS' מורחב ומוצגת בו רשימה של דגלים פוטנציאליים, עם התוויות משמאל לימין: 'ED', 'AT', '0', 'BS', 'BE', 'UV', '0' ו-'UP'.
שדות הנתונים של מאמת החשבונות בפרטי הכניסה של המפתח הציבורי.

בתהליך הרישום והאימות של מפתחות הגישה, השרת צריך לבדוק שהדגל UP הוא true, ואם דגל ה-UV הוא true או false, בהתאם לדרישה.

ציון הפרמטר userVerification

לפי מפרט WebAuthn, הגורם המוגבל יכול לבקש אימות משתמש עם פרמטר userVerification גם ביצירת פרטי כניסה וגם בטענת נכוֹנוּת (assertion). היא מקבלת 'preferred', 'required' או 'discouraged', כלומר:

  • 'preferred' (ברירת מחדל): עדיף להשתמש בשיטת אימות של משתמשים במכשיר, אבל אפשר לדלג עליה אם היא לא זמינה. פרטי הכניסה לתשובה מכילים את הערך true של סימון UV אם התבצע אימות משתמש, ו-false אם לא בוצע אימות UV.
  • 'required': חובה להפעיל שיטה לאימות המשתמש שזמינה במכשיר. אם אין מספר זמין, הבקשה תיכשל באופן מקומי. המשמעות היא שפרטי הכניסה של התגובה תמיד מוחזרים כאשר סימון ה-UV מוגדר כ-true.
  • 'discouraged': לא מומלץ להשתמש בשיטת אימות משתמש. עם זאת, בהתאם למכשיר, ייתכן שיתבצע אימות משתמש בכל מקרה, ודגלי ה-UV עשויים להכיל true או false.

קוד לדוגמה ליצירת מפתח גישה:

const publicKeyCredentialCreationOptions = {
  // ...
  authenticatorSelection: {
    authenticatorAttachment: 'platform',
    residentKey: 'required',
    requireResidentKey: true,
    userVerification: 'preferred'
  }
};

const credential = await navigator.credentials.create({
  publicKey: publicKeyCredentialCreationOptions
});

קוד לדוגמה לאימות מפתח גישה:

const publicKeyCredentialRequestOptions = {
  challenge: /* Omitted challenge data... */,
  rpId: 'example.com',
  userVerification: 'preferred'
};

const credential = await navigator.credentials.get({
  publicKey: publicKeyCredentialRequestOptions
});

באיזו אפשרות לבחור עבור userVerification?

הערך של userVerification שבו צריך להשתמש תלוי בדרישות האפליקציה ובצרכים של חוויית המשתמש.

מתי להשתמש בuserVerification='preferred'

אם חוויית המשתמש נמצאת בראש סדר העדיפויות, ניתן להשתמש ב-userVerification='preferred' על פני הגנה.

יש סביבות שבהן אימות המשתמשים מסובך יותר מההגנה. לדוגמה, ב-macOS שבו מזהה המגע לא זמין (כי המכשיר לא תומך בתכונה הזו, כי הוא מושבת או שהמכשיר נמצא במצב מעטפת), המשתמש יתבקש להזין את סיסמת המערכת שלו במקום זאת. התהליך הזה מקשה על המשתמש, והוא עשוי לנטוש את תהליך האימות לחלוטין. אם חשוב לך יותר לבטל את הקשיים, כדאי להשתמש ב-userVerification='preferred'.

צילום מסך של תיבת דו-שיח של מפתח גישה ב-macOS שמופיעה כשמזהה המגע לא זמין. תיבת הדו-שיח מכילה מידע כמו המקור שמבקש אימות וגם שם המשתמש. בפינה השמאלית העליונה של תיבת הדו-שיח מופיע הלחצן 'ביטול'.
תיבת דו-שיח של מפתח גישה מוצגת ב-macOS כשמזהה המגע לא זמין.

עם userVerification='preferred', הדגל של UV הוא true אם אימות המשתמש בוצע בהצלחה, ו-false אם מדלגים על אימות המשתמש. לדוגמה, ב-macOS שלא ניתן להשתמש ב-Touch ID, המשתמשים יתבקשו ללחוץ על הלחצן כדי לדלג על אימות המשתמש, ופרטי הכניסה למפתח הציבורי כוללים את סימון UV false.

דגל ה-UV יכול לשמש כסימן בניתוח הסיכונים. אם ניסיון הכניסה נראה מסוכן עקב גורמים אחרים, מומלץ להציג למשתמש עוד אתגרים בכניסה לחשבון אם אימות המשתמש לא בוצע.

מתי להשתמש בuserVerification='required'

כדאי להשתמש ב-userVerification='required' אם נראה לך שחיתות יש צורך גם ב-UP וגם בUV.

החיסרון של האפשרות הזו הוא שהכניסה לחשבון עלולה להיות קשה יותר למשתמשים. לדוגמה, ב-macOS שבו התכונה Touch ID לא זמינה, המשתמשים מתבקשים להזין את סיסמת המערכת.

עם userVerification='required', ניתן להבטיח שיתבצע אימות של המשתמש במכשיר. צריך לוודא שהשרת מוודא שסימון ה-UV הוא true.

סיכום

אימות המשתמש מאפשר לגורמים שמסתמכים על מפתחות גישה להעריך את הסבירות שבעל המכשיר ייכנס לחשבון. הם מחליטים אם לדרוש אימות של המשתמש או להפוך את האפשרות לאופציונלית בהתאם למידת הקריטיות של מנגנון הכניסה החלופי לחשבון, עד כמה הוא משפיע על תהליך המשתמש. צריך לוודא שהשרת בודק את הדגל UP ואת סימון ה-UV לאימות משתמשים של מפתחות גישה.