מפתחות גישה ופרטי כניסה אחרים של FIDO נועדו להחליף את הסיסמאות, אבל רובם גם מאפשרים למשתמשים לא להקליד שם משתמש. ההגדרה הזו מאפשרת למשתמשים לבצע אימות על ידי בחירת חשבון מתוך רשימת מפתחות הגישה שיש להם לאתר הנוכחי.
גרסאות קודמות של מפתחות אבטחה תוכננו כשיטות אימות דו-שלבי, ונדרשו בהן מזהים של פרטי כניסה פוטנציאליים, ולכן היה צורך בהזנת שם משתמש. פרטי הכניסה שמפתח אבטחה יכול למצוא בלי לדעת את המזהים שלהם נקראים פרטי כניסה ניתנים לגילוי. רוב פרטי הכניסה מסוג FIDO שנוצרים היום הם פרטי כניסה שאפשר לאתר, במיוחד מפתחות גישה שמאוחסנים במנהל סיסמאות או במפתח אבטחה מודרני.
כדי לוודא שפרטי הכניסה שלכם נוצרים כמפתחות גישה (פרטי כניסה שאפשר לגלות), צריך לציין את residentKey ואת requireResidentKey כשיוצרים את פרטי הכניסה.
צדדים נסמכים (RP) יכולים להשתמש באמצעי אימות שאפשר לגלות אותם על ידי השמטת allowCredentials במהלך אימות באמצעות מפתח גישה. במקרים כאלה, הדפדפן או המערכת מציגים למשתמש רשימה של מפתחות גישה זמינים, שמזוהים לפי המאפיין user.name שהוגדר בזמן היצירה. אם המשתמש בוחר אחת מהאפשרויות, הערך user.id
ייכלל בחתימה שמתקבלת. לאחר מכן השרת יכול להשתמש במזהה הזה או במזהה האישורים שהוחזר כדי לחפש את החשבון במקום להקליד שם משתמש.
ממשקי משתמש של בורר החשבונות, כמו אלה שדיברנו עליהם קודם, אף פעם לא מציגים פרטי כניסה שלא ניתן לגלות.
requireResidentKey וגם residentKey
כדי ליצור מפתח גישה, מציינים את הערכים הבאים של authenticatorSelection.residentKey ו-authenticatorSelection.requireResidentKey ב-navigator.credentials.create().
async function register () {
// ...
const publicKeyCredentialCreationOptions = {
// ...
authenticatorSelection: {
authenticatorAttachment: 'platform',
residentKey: 'required',
requireResidentKey: true,
}
};
const credential = await navigator.credentials.create({
publicKey: publicKeyCredentialCreationOptions
});
// This does not run until the user selects a passkey.
const credential = {};
credential.id = cred.id;
credential.rawId = cred.id; // Pass a Base64URL encoded ID string.
credential.type = cred.type;
// ...
}
residentKey:
'required': צריך ליצור פרטי כניסה שניתן לגלות. אם אי אפשר ליצור את המשתמש, מוחזרת השגיאהNotSupportedError.-
'preferred': ספק הזהויות מעדיף ליצור פרטי כניסה שניתן לגלות, אבל מקבל פרטי כניסה שלא ניתן לגלות. -
'discouraged': ה-RP מעדיף ליצור פרטי כניסה שלא ניתנים לגילוי, אבל מקבל פרטי כניסה שניתנים לגילוי.
requireResidentKey:
- המאפיין הזה נשמר לצורך תאימות לאחור מ-WebAuthn Level 1, גרסה ישנה יותר של המפרט. מגדירים את הערך
trueאם הערך שלresidentKeyהוא'required', אחרת מגדירים את הערךfalse.
allowCredentials
צדדים מסתמכים יכולים להשתמש ב-allowCredentials ב-navigator.credentials.get() כדי לשלוט בחוויית האימות באמצעות מפתח גישה. בדרך כלל יש שלושה סוגים של חוויות אימות באמצעות מפתח גישה:
הצגת בורר חשבונות מודאלי
באמצעות פרטי כניסה שניתן לגלות, ספקי RP יכולים להציג למשתמש חלון קופץ לבחירת חשבון, כדי שהמשתמש יוכל לבחור חשבון להתחברות, ולאחר מכן לאמת את המשתמש. האפשרות הזו מתאימה לתהליך אימות באמצעות מפתח גישה שמתחיל בלחיצה על לחצן שמוקדש לאימות באמצעות מפתח גישה.
כדי להשיג את חוויית המשתמש הזו, צריך להשמיט את הפרמטר allowCredentials ב-navigator.credentials.get() או להעביר מערך ריק.
async function authenticate() {
// ...
const publicKeyCredentialRequestOptions = {
// Server generated challenge:
challenge: ****,
// The same RP ID as used during registration:
rpId: 'example.com',
// You can omit `allowCredentials` as well:
allowCredentials: []
};
const credential = await navigator.credentials.get({
publicKey: publicKeyCredentialRequestOptions,
signal: abortController.signal
});
// This does not run until the user selects a passkey.
const credential = {};
credential.id = cred.id;
credential.rawId = cred.id; // Pass a Base64URL encoded ID string.
credential.type = cred.type;
// ...
}
הצגת מילוי אוטומטי של טופס עם מפתח גישה
החלון לבחירת חשבון שמתואר למעלה מתאים אם רוב המשתמשים משתמשים במפתחות גישה והם זמינים במכשיר המקומי. למשתמשים שאין להם מפתחות גישה מקומיים, עדיין יופיע תיבת הדו-שיח המודאלית, והם יוכלו להציג מפתח גישה ממכשיר אחר. במהלך המעבר של המשתמשים למפתחות גישה, יכול להיות שתרצו שהמשתמשים שלא הגדירו מפתח גישה לא יראו את ממשק המשתמש הזה.
במקום זאת, יכול להיות שהאפשרות לבחור מפתח גישה תופיע בהצעות למילוי אוטומטי של השדות בטופס כניסה רגיל, לצד שמות משתמשים וסיסמאות שמורים. כך, משתמשים עם מפתחות גישה יכולים לבחור את מפתח הגישה שלהם כדי למלא את טופס הכניסה, משתמשים עם זוגות של שם משתמש וסיסמה שמורים יכולים לבחור אותם, ומשתמשים בלי מפתחות גישה או זוגות שמורים יכולים להקליד את שם המשתמש והסיסמה שלהם.
חוויית המשתמש הזו אידיאלית כשספק הזהויות נמצא בתהליך העברה עם שימוש משולב בסיסמאות ובמפתחות גישה.
כדי להשיג את חוויית המשתמש הזו, בנוסף להעברת מערך ריק למאפיין allowCredentials או להשמטת הפרמטר, צריך לציין mediation: 'conditional' ב-navigator.credentials.get() ולהוסיף הערה לשדה להזנת קלט username ב-HTML עם autocomplete="username webauthn" או לשדה להזנת קלט password עם autocomplete="password webauthn".
הקריאה ל-navigator.credentials.get() לא תגרום להצגת ממשק משתמש, אבל אם המשתמש יתמקד בשדה להזנת קלט עם ההערות, כל מפתחות הגישה הזמינים ייכללו באפשרויות המילוי האוטומטי. אם המשתמש בוחר אחת מהאפשרויות, הוא יעבור את האימות הרגיל לפתיחת הנעילה במכשיר, ורק אז ההבטחה שמוחזרת על ידי .get() תסתיים עם תוצאה. אם המשתמש לא בוחר מפתח גישה, ההבטחה אף פעם לא מתממשת.
async function authenticate() {
// ...
const publicKeyCredentialRequestOptions = {
// Server generated challenge:
challenge: ****,
// The same RP ID as used during registration:
rpId: 'example.com',
// You can omit `allowCredentials` as well:
allowCredentials: []
};
const cred = await navigator.credentials.get({
publicKey: publicKeyCredentialRequestOptions,
signal: abortController.signal,
// Specify 'conditional' to activate conditional UI
mediation: 'conditional'
});
// This does not run until the user selects a passkey.
const credential = {};
credential.id = cred.id;
credential.rawId = cred.id; // Pass a Base64URL encoded ID string.
credential.type = cred.type;
// ...
}
<input type="text" name="username" autocomplete="username webauthn" ...>
במאמר כניסה באמצעות מפתח גישה דרך מילוי אוטומטי של טופס ובשיעור ה-Codelab הטמעה של מפתחות גישה באמצעות מילוי אוטומטי של טופס באפליקציית אינטרנט מוסבר איך ליצור את חוויית המשתמש הזו.
אימות מחדש
במקרים מסוימים, כמו כשמשתמשים במפתחות גישה לאימות מחדש, המזהה של המשתמש כבר ידוע. במקרה כזה, אנחנו רוצים להשתמש במפתח גישה בלי שהדפדפן או מערכת ההפעלה יציגו צורה כלשהי של בוחר חשבונות. כדי לעשות זאת, צריך להעביר רשימה של מזהי אישורים בפרמטר allowCredentials.
במקרה כזה, אם יש אישורים מקומיים ששמם מופיע ברשימה, המשתמש יתבקש לפתוח את הנעילה במכשיר באופן מיידי. אם לא, המשתמש מתבקש להציג מכשיר אחר (טלפון או מפתח אבטחה) שבו יש פרטי כניסה תקינים.
כדי ליצור את חוויית המשתמש הזו, צריך לספק רשימה של מזהי אמצעי אימות למשתמש שמבצע את הכניסה. ה-RP צריך להיות מסוגל לשלוח שאילתות לגביהם כי המשתמש כבר מוכר. צריך לספק מזהים של פרטי כניסה כאובייקטים מסוג PublicKeyCredentialDescriptor במאפיין allowCredentials ב-navigator.credentials.get().
async function authenticate() {
// ...
const publicKeyCredentialRequestOptions = {
// Server generated challenge:
challenge: ****,
// The same RP ID as used during registration:
rpId: 'example.com',
// Provide a list of PublicKeyCredentialDescriptors:
allowCredentials: [{
id: ****,
type: 'public-key',
transports: [
'internal',
'hybrid'
]
}, {
id: ****,
type: 'public-key',
transports: [
'internal',
'hybrid'
]
}, ...]
};
const credential = await navigator.credentials.get({
publicKey: publicKeyCredentialRequestOptions,
signal: abortController.signal
});
// This does not run until the user selects a passkey.
const credential = {};
credential.id = cred.id;
credential.rawId = cred.id; // Pass a Base64URL encoded ID string.
credential.type = cred.type;
// ...
}
אובייקט PublicKeyCredentialDescriptor מורכב מהרכיבים הבאים:
-
id: מזהה של פרטי הכניסה של המפתח הציבורי שה-RP קיבל במהלך רישום מפתח הגישה. type: בדרך כלל הערך בשדה הזה הוא'public-key'.-
transports: רמז לגבי פרוטוקולי התעבורה הנתמכים במכשיר שבו נמצאים פרטי הכניסה האלה. הדפדפנים משתמשים ברמז הזה כדי לבצע אופטימיזציה של ממשק המשתמש שבו המשתמש מתבקש להציג מכשיר חיצוני. אם מספקים את הרשימה הזו, היא צריכה להכיל את התוצאה של הקריאה ל-getTransports()במהלך הרישום של כל אישור.
סיכום
פרטי כניסה שניתן לגלות מאפשרים למשתמשים לדלג על הזנת שם משתמש, וכך חוויית הכניסה באמצעות מפתח גישה הופכת לידידותית הרבה יותר. בעזרת השילוב של residentKey, requireResidentKey ו-allowCredentials, ספקי RP יכולים ליצור חוויות התחברות ש:
- הצגת בורר חשבונות מודאלי.
- הצגת מילוי אוטומטי של טופס עם מפתח גישה.
- אימות מחדש.
חשוב להשתמש בחוכמה בפרטי כניסה שגלויים לכולם. כך תוכלו לעצב חוויות כניסה מתוחכמות באמצעות מפתחות גישה, שיהיו חלקות למשתמשים ויגדילו את הסיכוי שהם יתקשרו עם האתר או האפליקציה.