איך לשמור על עקביות בין מפתחות הגישה לבין פרטי הכניסה בשרת באמצעות Signal API

תאריך הפרסום: 12 בנובמבר 2024

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

תאימות

Chrome במחשב תומך ב-Signal API החל מגרסה 132. מנהל הסיסמאות של Google יכול לעדכן את מפתחות הגישה בהתאם לאות. ספקי מפתחות גישה שמבוססים על תוספים ל-Chrome יכולים להחליט אם לשקף את האות או לא.

התמיכה ב-Chrome ל-Android תגיע בהמשך.

יש תמיכה ב-Safari, אבל היא עדיין לא הופעלה. הצוות של Firefox עדיין לא שיתף את הדעה שלו.

רקע

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

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

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

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

Signal API

Signal API הוא ממשק API של WebAuthn שמסיר את הבלבול הזה על ידי מתן אפשרות ל-RPs לסמן שינויים לספק מפתח הגישה. יש שלוש שיטות:

אות לכך שפרטי כניסה לא קיימים

const credential = await navigator.credentials.get({ ... });
const payload = credential.toJSON();

const result = await fetch('/login', { ... });

// Detect authentication failure due to lack of the credential
if (result.status === 404) {
  // Feature detection
  if (PublicKeyCredential.signalUnknownCredential) {
    await PublicKeyCredential.signalUnknownCredential({
      rpId: "example.com",
      credentialId: "vI0qOggiE3OT01ZRWBYz5l4MEgU0c7PmAA" // base64url encoded credential ID
    });
  } else {
    // Encourage the user to delete the passkey from the password manager nevertheless.
    ...
  }
}

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

אפשר להפעיל את ה-API הזה כשההתחברות באמצעות מפתח גישה נכשלה בגלל היעדר פרטי כניסה. כך, ה-RP יכול למנוע מהמשתמש לנסות להיכנס באמצעות מפתח גישה שאין לו פרטי כניסה משויכים. בניגוד ל-signalAllAcceptedCredentials, בשיטה הזו לא צריך להעביר את כל רשימת מזהי פרטי הכניסה, לכן כדאי להשתמש בה בכל פעם שהמשתמש לא מאומת, כדי לא לחשוף את מספר מפתחות הגישה של משתמש נתון.

תיבת דו-שיח שמופיעה כשמוחקים מפתח גישה ממנהל הסיסמאות של Google ב-Chrome.
תיבת דו-שיח שמוצגת כשמפתח גישה נמחק ממנהל הסיסמאות של Google ב-Chrome.

שליחת אות לגבי רשימה של פרטי כניסה שמורים

// After a user deletes a passkey or a user is signed in.

// Feature detection
if (PublicKeyCredential.signalAllAcceptedCredentials) {
  await PublicKeyCredential.signalAllAcceptedCredentials({
    rpId: "example.com",
    userId: "M2YPl-KGnA8", // base64url encoded user ID
    allAcceptedCredentialIds: [ // A list of base64url encoded credential IDs
      "vI0qOggiE3OT01ZRWBYz5l4MEgU0c7PmAA",
      ...
    ]
  });
}

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

צריך להפעיל את ה-API הזה כשמשתמש מוחק מפתח גישה ב-RP ובכל כניסה, כדי שספק מפתחות הגישה יוכל לשמור רשימה מסונכרנת של מפתחות הגישה.

אות לעדכון שם המשתמש והשם המוצג

// After a user updated their username and/or display name
// or a user is signed in.

// Feature detection
if (PublicKeyCredential.signalCurrentUserDetails) {
  await PublicKeyCredential.signalCurrentUserDetails({
    rpId: "example.com",
    userId: "M2YPl-KGnA8", // base64url encoded user ID
    name: "a.new.email.address@example.com", // username
    displayName: "J. Doe"
  });
} else {
}

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

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

תיבת דו-שיח שמופיעה כשמתעדכנים המטא-נתונים של מפתח גישה במנהל הסיסמאות של Google ב-Chrome.
תיבת דו-שיח שמוצגת כשמתעדכנים את המטא-נתונים של מפתח גישה במנהל הסיסמאות של Google ב-Chrome.

סיכום

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

למידע נוסף על מפתחות גישה, אפשר להתחיל במאמר כניסה ללא סיסמה באמצעות מפתחות גישה.