איך יצרנו את הכרטיסייה WebAuthn ל-Chrome DevTools

Fawaz Mohammad
Fawaz Mohammad
Nina Satragno
Nina Satragno

Web Authentication API, שנקרא גם WebAuthn, מאפשר לשרתים להשתמש בהצפנת מפתחות ציבוריים – במקום סיסמאות – כדי לרשום ולאמת משתמשים. לשם כך, הוא מאפשר שילוב בין השרתים האלה לבין מאמתים חזקים. מאמתים כאלה יכולים להיות מכשירים פיזיים ייעודיים (למשל מפתחות אבטחה) או מכשירים משולבים בפלטפורמות (למשל קוראי טביעות אצבע). מידע נוסף על WebAuthn זמין בכתובת webauthn.guide.

בעיות של מפתחים

לפני הפרויקט הזה, לא הייתה ב-WebAuthn תמיכה מקורית בניפוי באגים ב-Chrome. מפתח שפיתח אפליקציה שהשתמשה ב-WebAuth נזקק לגישה למאמתים פיזיים. זה היה קשה במיוחד משתי סיבות:

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

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

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

פתרון: כרטיסייה חדשה של WebAuthn

הכרטיסייה WebAuthn DevTools מאפשרת למפתחים לדמות את מאמתי WebAuthn, להתאים אישית את היכולות שלהם ולבדוק את המצבים שלהם, וכך לפתור באגים ב-WebAuthn בקלות רבה יותר.

כרטיסייה חדשה של WebAuthn

הטמעה

הוספת תמיכה בניפוי באגים ל-WebAuthn הייתה תהליך בשני חלקים.

תהליך בשני חלקים

חלק 1: הוספת דומיין WebAuthn לפרוטוקול של כלי הפיתוח של Chrome

קודם כל, הטמענו דומיין חדש בפרוטוקול של כלי הפיתוח של Chrome‏ (CDP) שמתחבר למטפל שמתקשר לקצה העורפי של WebAuthn.

ה-CDP מחבר את הקצה הקדמי של DevTools ל-Chromium. במקרה שלנו, השתמשנו בפעולות הדומיין של WebAuthn כדי ליצור גשר בין הכרטיסייה של WebAuthn DevTools לבין ההטמעה של WebAuthn ב-Chromium.

הדומיין של WebAuthn מאפשר להפעיל ולהשבית את הסביבה של רכיב האימות הווירטואלי, שמנתקת את הדפדפן מ-Authenticator Discovery האמיתי ומחברת אותו ל-Virtual Discovery במקום זאת.

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

(לקריאת הקוד)

חלק 2: פיתוח הכרטיסייה שמוצגת למשתמשים

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

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

המודל

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

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

(לקריאת הקוד)

התצוגה

כרטיסייה חדשה של WebAuthn

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

  1. סרגל כלים להפעלת סביבה של רכיב אימות וירטואלי.
  2. קטע להוספת מאמתים.
  3. קטע לאימותים שנוצרו.

(לקריאת הקוד)

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

סרגל כלים

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

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

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

הוספת הקטע 'מאמתי חשבונות'

הוספת הקטע 'מאמתי חשבונות'

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

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

התצוגה של מאמת החשבונות

התצוגה של מאמת החשבונות

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

שם מאמת החשבונות

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

טבלת פרטי הכניסה

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

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

לחצן 'פעיל'

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

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

אחת מהאתגרים המעניינים שניצבנו בהם במהלך ההוספה של הלחצן הפעיל הייתה הימנעות ממצב מרוץ (race condition). למשל, נבחן את התרחיש הבא:

  1. המשתמש לוחץ על לחצן הבחירה Active (פעיל) לרכיב האימות X, ושולח בקשה ל-CDP להגדיר את X כפעיל. לחצן הבחירה Active עבור X מסומן, וכל שאר האפשרויות לא מסומנות.

  2. מיד לאחר מכן, המשתמש לוחץ על לחצן הבחירה Active (פעיל) לאימות Y, ושולח בקשה ל-CDP להגדיר את Y כפעיל. לחצן הבחירה Active (פעיל) עבור Y מסומן, וכל שאר הלחצנים, כולל לחצן הבחירה של X, לא מסומנים.

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

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

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

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

כך זה נראה:


 async _setActiveAuthenticator(authenticatorId) {
   await this._clearActiveAuthenticator();
   await this._model.setAutomaticPresenceSimulation(authenticatorId, true);
   this._activeId = authenticatorId;
   this._updateActiveButtons();
 }
 
 _updateActiveButtons() {
   const authenticators = this._authenticatorsView.getElementsByClassName('authenticator-section');
   Array.from(authenticators).forEach(authenticator => {
     authenticator.querySelector('input.dt-radio-button').checked =
         authenticator.getAttribute('data-authenticator-id') === this._activeId;
   });
 }
 
 async _clearActiveAuthenticator() {
   if (this._activeId) {
     await this._model.setAutomaticPresenceSimulation(this._activeId, false);
   }
   this._activeId = null;
 }

מדדי שימוש

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

  1. ספירה של כל פעם שכרטיסיית WebAuthn נפתחה ב-DevTools. האפשרות הזו עלולה להוביל לספירה מוגזמת, כי משתמש יכול לפתוח את הכרטיסייה בלי להשתמש בה בפועל.

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

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

סיכום

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

ריכזנו כאן כמה מקורות מידע שיעזרו לכם להבין טוב יותר את WebAuthn:

הורדת הערוצים לתצוגה מקדימה

מומלץ להשתמש ב-Chrome Canary, ב-Dev או ב-Beta כדפדפן הפיתוח שמוגדר כברירת מחדל. ערוצי התצוגה המקדימה האלה מעניקים לכם גישה לתכונות העדכניות ביותר של DevTools, מאפשרים לכם לבדוק ממשקי API מתקדמים לפלטפורמות אינטרנט ולמצוא בעיות באתר לפני שהמשתמשים שלכם יעשו זאת.

יצירת קשר עם צוות כלי הפיתוח ל-Chrome

אתם יכולים להשתמש באפשרויות הבאות כדי לדון בתכונות החדשות, בעדכונים או בכל דבר אחר שקשור ל-DevTools.