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

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

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

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

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

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

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

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

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

ציון הפרמטר userVerification

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

  • 'preferred' (ברירת המחדל): מומלץ להשתמש בשיטת אימות משתמש במכשיר, אבל אפשר לדלג עליה אם היא לא זמינה. פרטי הכניסה בתגובה מכילים את ערך הדגל של אימות המשתמש (UV) – true אם בוצע אימות משתמש, ו-false אם לא בוצע אימות משתמש.
  • '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, שבו Touch ID לא זמין (כי המכשיר לא תומך בו, הוא מושבת או שהמכשיר נמצא במצב צדפה), המשתמש יתבקש להזין את סיסמת המערכת במקום זאת. המצב הזה יוצר חיכוך, והמשתמש עלול לוותר על האימות לגמרי. אם חשוב לכם להפחית את החיכוך, השתמשו ב-userVerification='preferred'.

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

כשמשתמשים ב-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 לאימות משתמש של מפתח גישה.