ליצור תהליך כניסה באמצעות מפתחות גישה, תוך התאמה למשתמשי סיסמאות קיימים.
מפתחות גישה מחליפים את הסיסמאות ומאפשרים להשתמש בחשבונות משתמשים באינטרנט בצורה בטוחה, פשוטה ונוחה יותר. עם זאת, המעבר מאימות שמבוסס על סיסמה לאימות שמבוסס על מפתח גישה עלול לסבך את חוויית המשתמש. השימוש במילוי אוטומטי של טפסים כדי להציע מפתחות גישה יכול לעזור לכם ליצור חוויה מאוחדת.
למה כדאי להשתמש במילוי אוטומטי של טפסים כדי להיכנס לחשבון באמצעות מפתח גישה?
מפתח גישה מאפשר למשתמש להיכנס לאתר רק באמצעות טביעת אצבע, זיהוי פנים או קוד אימות של המכשיר.
באופן אידיאלי, לא יהיו משתמשים עם סיסמה ותהליך האימות יכול להיות פשוט כמו לחצן כניסה יחיד. כשהמשתמש מקשיב על הלחצן, מופיעה תיבת דו-שיח לבחירת חשבון. המשתמש יכול לבחור חשבון, לבטל את נעילת המסך כדי לאמת ולהיכנס.
עם זאת, המעבר מסיסמה לאימות שמבוסס על מפתח גישה יכול להיות מאתגר. כשמשתמשים עוברים להשתמש במפתחות גישה, עדיין יהיו מי שישתמשו בסיסמאות ובאתרים שלא יצטרכו לספק מענה לשני סוגי המשתמשים. לא סביר שהמשתמשים עצמם יזכרו באילו אתרים הם עברו להשתמש במפתחות גישה, ולכן בקשה מהם לבחור מראש את השיטה שבה הם רוצים להשתמש תהיה חוויית משתמש גרועה.
מפתחות הגישה הם גם טכנולוגיה חדשה. הסבר על התכונות האלה ולוודא שהמשתמשים מרגישים בנוח להשתמש בהן יכולים להיות אתגר לאתרים. כדי לפתור את שתי הבעיות, אנחנו יכולים להסתמך על חוויות משתמש מוכרות של מילוי אוטומטי של סיסמאות.
ממשק משתמש מותנה
כדי ליצור חוויית משתמש יעילה גם למשתמשים עם מפתחות גישה וגם למשתמשים עם סיסמאות, תוכלו לכלול מפתחות גישה בהצעות למילוי אוטומטי. התכונה הזו נקראת ממשק משתמש מותנה והיא חלק מתקן WebAuthn.
ברגע שהמשתמש מקשיב על שדה הקלט של שם המשתמש, תיפתח תיבת דו-שיח עם הצעות למילוי אוטומטי, שבה מודגשים מפתחות הגישה השמורים לצד הצעות למילוי אוטומטי של סיסמה. לאחר מכן המשתמש יכול לבחור חשבון ולהשתמש בנעילת המסך של המכשיר כדי להיכנס.
כך משתמשים יוכלו להיכנס לאתר באמצעות הטופס הקיים כאילו שום דבר לא השתנה, אבל עם היתרון הנוסף של האבטחה של מפתחות גישה, אם יש להם כזה.
איך זה עובד
כדי לבצע אימות באמצעות מפתח גישה, משתמשים ב-WebAuthn API.
ארבעת הרכיבים בתהליך האימות באמצעות מפתח גישה הם: המשתמש:
- קצה עורפי: שרת הקצה העורפי שמכיל את מסד הנתונים של החשבונות שבו מאוחסנים המפתח הציבורי ומטא-נתונים אחרים לגבי מפתח הגישה.
- חזית: החזית שלכם, שמתקשרת עם הדפדפן ושולחת בקשות אחזור לקצה העורפי.
- דפדפן: הדפדפן של המשתמש שבו פועל הקוד של JavaScript.
- מאמת: מאמת החשבונות של המשתמש שיוצר ומאחסן את מפתח הגישה. המכשיר עשוי להיות באותו מכשיר שבו נמצא הדפדפן (למשל, כשמשתמשים ב-Windows Hello) או במכשיר אחר, כמו טלפון.
- ברגע שמשתמש מגיע לממשק הקצה, הוא מבקש אתגר מהקצה העורפי כדי לבצע אימות באמצעות מפתח גישה, וקורא ל-
navigator.credentials.get()
כדי להתחיל את תהליך האימות באמצעות מפתח גישה. הפונקציה מחזירהPromise
. - כשהמשתמש שם את הסמן בשדה הכניסה, בדפדפן מוצגת תיבת דו-שיח למילוי אוטומטי של סיסמאות, כולל מפתחות גישה. תיבת דו-שיח לאימות תופיע אם המשתמש יבחר מפתח גישה.
- אחרי שהמשתמש יאמת את זהותו באמצעות נעילת המסך של המכשיר, ההבטחה תטופל ופרטי הכניסה למפתח ציבורי יוחזרו לממשק הקצה.
- חזית האתר שולחת את פרטי הכניסה של המפתח הציבורי לקצה העורפי. הקצה העורפי מאמת את החתימה מול המפתח הציבורי של החשבון התואם במסד הנתונים. אם הפעולה מצליחה, המשתמש ייכנס לחשבון.
אימות באמצעות מפתח גישה באמצעות מילוי אוטומטי של טפסים
כשמשתמש רוצה להיכנס לחשבון, אפשר לבצע קריאה מותנית ל-WebAuthn get
כדי לציין שמפתחות גישה עשויים להיכלל בהצעות למילוי אוטומטי. קריאה מותנית ל-navigator.credentials.get()
API של WebAuthn לא מציגה ממשק משתמש ונשארת בהמתנה עד שהמשתמש בוחר חשבון להיכנס איתו מהצעות המילוי האוטומטי. אם המשתמש בוחר מפתח גישה, הדפדפן יפתור את ההבטחה באמצעות פרטי כניסה במקום למלא את טופס הכניסה. לאחר מכן, הדף אחראי להכניס את המשתמש.
הוספת הערה לשדה להזנת קלט בטופס
מוסיפים מאפיין autocomplete
לשדה של שם המשתמש input
, אם צריך.
מוסיפים את username
ו-webauthn
בתור האסימונים שלו כדי לאפשר לו להציע מפתחות גישה.
<input type="text" name="username" autocomplete="username webauthn" ...>
זיהוי תכונות
לפני שמפעילים קריאה מותנית ל-WebAuthn API, צריך לבדוק אם:
- הדפדפן תומך ב-WebAuthn עם
PublicKeyCredential
.
- הדפדפן תומך בממשק משתמש מותנה של WebAuthn באמצעות
PublicKeyCredenital.isConditionalMediationAvailable()
.
// Availability of `window.PublicKeyCredential` means WebAuthn is usable.
if (window.PublicKeyCredential &&
PublicKeyCredential.isConditionalMediationAvailable) {
// Check if conditional mediation is available.
const isCMA = await PublicKeyCredential.isConditionalMediationAvailable();
if (isCMA) {
// Call WebAuthn authentication
}
}
אחזור אתגר משרת ה-RP
אחזור אתגר משרת RP שנדרש כדי לקרוא ל-navigator.credentials.get()
:
challenge
: אתגר שנוצר על ידי השרת ב-ArrayBuffer. הפעולה הזו נדרשת כדי למנוע התקפות של שליחה מחדש. חשוב ליצור אתגר חדש בכל ניסיון כניסה ומתעלמים ממנו אחרי פרק זמן מסוים או אחרי שהאימות של ניסיון כניסה נכשל. זה כמו אסימון CSRF.allowCredentials
: מערך של פרטי כניסה קבילים לאימות הזה. מעבירים מערך ריק כדי לאפשר למשתמש לבחור מפתח גישה זמין מתוך רשימה שמוצגת בדפדפן.userVerification
: מציין אם אימות המשתמש באמצעות נעילת המסך של המכשיר הוא"required"
,"preferred"
או"discouraged"
. ברירת המחדל היא"preferred"
, כלומר האימות עשוי לדלג על אימות המשתמש. מגדירים את הערך ל-"preferred"
או משמיטים את הנכס.
קריאה ל-WebAuthn API עם הדגל conditional
כדי לאמת את המשתמש
קוראים ל-navigator.credentials.get()
כדי להתחיל להמתין לאימות המשתמש.
// To abort a WebAuthn call, instantiate an `AbortController`.
const abortController = new AbortController();
const publicKeyCredentialRequestOptions = {
// Server generated challenge
challenge: ****,
// The same RP ID as used during registration
rpId: 'example.com',
};
const credential = await navigator.credentials.get({
publicKey: publicKeyCredentialRequestOptions,
signal: abortController.signal,
// Specify 'conditional' to activate conditional UI
mediation: 'conditional'
});
rpId
: מזהה RP הוא דומיין, ואתר יכול לציין את הדומיין שלו או סיומת שניתן לרשום. הערך הזה חייב להתאים לערך של rp.id ששימש ליצירת מפתח הגישה.
חשוב לציין את mediation: 'conditional'
כדי שהבקשה תהיה מותנית.
שולחים את פרטי הכניסה של המפתח הציבורי שהוחזרו לשרת ה-RP
אחרי שהמשתמש בוחר חשבון ומביע הסכמה באמצעות נעילת המסך של המכשיר, ההתחייבות מתקבלת ומוחזר אובייקט PublicKeyCredential
לקצה הקדמי של RP.
יש כמה סיבות אפשריות לדחייה של הבטחה. צריך לטפל בשגיאות בהתאם, בהתאם למאפיין name
של האובייקט Error
:
NotAllowedError
: המשתמש ביטל את הפעולה.- חריגים אחרים: קרה משהו בלתי צפוי. הדפדפן מציג למשתמש תיבת דו-שיח עם הודעת שגיאה.
אובייקט פרטי הכניסה של המפתח הציבורי מכיל את המאפיינים הבאים:
id
: המזהה בקידוד base64 URL של פרטי הכניסה המאומתים של מפתח הגישה.rawId
: גרסה של מזהה פרטי הכניסה ב-ArrayBuffer.response.clientDataJSON
: ArrayBuffer של נתוני לקוח. השדה הזה מכיל מידע כמו האתגר והמקור ששרת ה-RP יצטרך לאמת.response.authenticatorData
: ArrayBuffer של נתוני אימות. השדה הזה מכיל מידע כמו מזהה RP.response.signature
: ArrayBuffer של החתימה. הערך הזה הוא הליבה של פרטי הכניסה, וצריך לאמת אותו בשרת.response.userHandle
: ArrayBuffer שמכיל את מזהה המשתמש שהוגדר בזמן היצירה. אפשר להשתמש בערך הזה במקום במזהה פרטי הכניסה, אם השרת צריך לבחור את ערכי המזהה שבהם הוא משתמש, או אם הקצה העורפי רוצה להימנע מיצירת אינדקס של מזהי פרטי הכניסה.authenticatorAttachment
: הפונקציה מחזירה את הערךplatform
כשפרטי הכניסה האלה הגיעו מהמכשיר המקומי. אחרת,cross-platform
, במיוחד כשהמשתמש השתמש בטלפון כדי להיכנס לחשבון. אם המשתמש נאלץ להשתמש בטלפון כדי להיכנס לחשבון, כדאי לבקש ממנו ליצור מפתח גישה במכשיר המקומי.type
: השדה הזה תמיד מוגדר ל-"public-key"
.
אם אתם משתמשים בספרייה כדי לטפל באובייקט פרטי הכניסה של המפתח הציבורי בשרת ה-RP, מומלץ לשלוח את האובייקט כולו לשרת אחרי שמקודדים אותו באופן חלקי באמצעות base64url.
אימות החתימה
כשמקבלים את פרטי הכניסה של המפתח הציבורי בשרת, מעבירים אותם לספריית FIDO כדי לעבד את האובייקט.
מחפשים את מזהה פרטי הכניסה התואם באמצעות הנכס id
(אם צריך לקבוע את חשבון המשתמש, משתמשים בנכס userHandle
שהוא הערך של user.id
שציינתם כשיצרתם את פרטי הכניסה). בודקים אם אפשר לאמת את signature
של פרטי הכניסה באמצעות המפתח הציבורי המאוחסן. כדי לעשות זאת, מומלץ להשתמש בספרייה או בפתרון בצד השרת במקום לכתוב קוד משלכם. ספריות קוד פתוח זמינות במאגר GitHub של awesome-webauth.
אחרי האימות של פרטי הכניסה באמצעות מפתח ציבורי תואם, מאשרים את הכניסה של המשתמש.
הוראות מפורטות יותר זמינות במאמר אימות מפתח גישה בצד השרת