מפתחות גישה בתוך iframe

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

זיהוי מודלים של איומים

לפני שמפעילים מפתחות גישה (WebAuthn) בתוך מסגרות משנה, חשוב להבין את תרחישי השימוש לרעה שאתם מנסים להתגונן מפניהם:

  • מעקב באמצעות הזרקת iframe מוסתר: תוקף מפעיל הנחיה של WebAuthn מהדומיין שלו באמצעות מודעה או ווידג'ט באתר מהימן, וגורם למשתמשים לאשר מפתח גישה בלי לראות את ההקשר. הפעולה הזו מקשרת את הזהות של המשתמש לחשבון שנמצא בשליטת התוקף, כדי לאסוף נתונים.
  • שכבת-על חזותית וגניבת קליקים (הונאת ממשק משתמש): דף אב זדוני מעבד את ה-iframe של האימות באופן בלתי נראה באמצעות CSS רגיל, ומציג שכבת-על של רכיב בממשק המשתמש מזויף כדי לגנוב קליק שמפעיל תהליך אימות. אם המשתמש משלים את ההנחיה בטעות, זה עלול לגרום לחטיפת סשן או לפעולות לא מורשות בכפייה.

כדי להתמודד עם האיומים האלה, כדאי לפעול לפי השיטות המומלצות הבאות:

למסמך ברמה העליונה (הפריים העליון):

למסמך המוטמע (iframe):

בשני המסמכים:

הפעלת האצלה באמצעות מדיניות הרשאות

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

טוקנים של תכונות

ב-WebAuthn נעשה שימוש בשני אסימונים שונים:

  • publickey-credentials-get: מעניק הרשאה לתהליכי כניסה באמצעות מפתח גישה (navigator.credentials.get()).
  • publickey-credentials-create: מעניק הרשאה לתהליכי רישום של מפתחות גישה (navigator.credentials.create()).

דרישות להפעלה

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

Permissions-Policy: publickey-credentials-get=(self "https://embedded-auth.example.com")

מדיניות ההרשאות: תאימות ל-publickey-credentials-get:

Browser Support

  • Chrome: 88.
  • Edge: 88.
  • Firefox: not supported.
  • Safari: not supported.

Source

מדיניות הרשאות: תאימות ל-publickey-credentials-create:

Browser Support

  • Chrome: 88.
  • Edge: 88.
  • Firefox: not supported.
  • Safari: not supported.

Source

  • המאפיין allow של HTML: בתגי העיצוב של HTML, צריך גם להצהיר על הפעלת התכונה ברכיב <iframe>.
<iframe src="https://embedded-auth.example.com?nonce=deadbeef12345678&client=https%3A%2F%2Fembedded-auth.example.com" allow="publickey-credentials-get"></iframe>

תאימות של iframe עם allow="publickey-credentials-get":

Browser Support

  • Chrome: 84.
  • Edge: 84.
  • Firefox: 118.
  • Safari: not supported.

תאימות של iframe עם allow="publickey-credentials-create":

Browser Support

  • Chrome: not supported.
  • Edge: not supported.
  • Firefox: 123.
  • Safari: not supported.

הפעלת קובצי Cookie מחולקים של צד שלישי

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

כדי להתגבר על המכשולים האלה, צריך להגדיר את קובצי ה-Cookie של הסשן עם המאפיינים SameSite: None, Secure ו-Partitioned. מנגנון הפלטפורמה המאוחד הזה מבטיח מצב מתמשך בתוך ה-iframe, תוך התחשבות באמצעי הבקרה של הפרטיות ברמת הדפדפן.

הגדרה של SameSite: None

SameSite: None מציין באופן מפורש קובץ Cookie לגישה חוצת-אתרים, ומאפשר לשלוח אותו עם בקשות שמוגשות מהקשר של צד שלישי (כמו iframe). המאפיין הזה הוא תנאי מוקדם לפעולה של קובצי Cookie בתרחישים של בקשות חוצות-מקורות, אבל צריך לשלב אותו עם המאפיין Secure כדי שדפדפנים מודרניים יקבלו אותו.

הגדרה של Partitioned

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

הגנה על נקודת הקצה באמצעות Content Security Policy

בזמן שמדיניות ההרשאות קובעת אם אפשר להריץ WebAuthn ב-iframe, ‏ Content Security Policy‏ (CSP) קובעת למי מותר לארח את ה-iframe.

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

שימוש ב-frame-ancestors

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

Content-Security-Policy: frame-ancestors 'self' https://parent-site.example.com;

Content Security Policy: תאימות של frame-ancestors:

Browser Support

  • Chrome: 40.
  • Edge: 15.
  • Firefox: 58.
  • Safari: 10.

Source

הגדרה של X-Frame-Options

הכותרת מדור קודם X-Frame-Options תומכת ביכולת דומה, אבל רק באפשרויות בינאריות (DENY או SAMEORIGIN). כדאי להגדיר גם את CSP frame-ancestors וגם את X-Frame-Options: DENY למקרה שהדפדפן לא תומך ב-CSP. ל-CSP תמיד יש עדיפות במקומות שבהם היא נתמכת.

X-Frame-Options: DENY

תאימות של X-Frame-Options:

Browser Support

  • Chrome: 4.
  • Edge: 12.
  • Firefox: 4.
  • Safari: 4.

Source

מהימנות, אבל אימות בצד השרת

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

מטען ייעודי (payload) של נתוני לקוחות

נתוני הלקוח של WebAuthn כוללים פרמטרים שנועדו לעזור לכם לאמת את ההקשר של בקשה שמוגשת בתוך iframe:

  • crossOrigin (בוליאני): מציין אם הופעל WebAuthn API בתוך iframe ממקורות שונים. אם הארכיטקטורה שלכם מסתמכת על תגי iframe, השרת חייב לאכוף שהדגל הזה הוא true.
  • topOrigin (מחרוזת): המקור של הקשר הגלישה ברמה העליונה (מה שמוצג בסרגל הכתובות של הדפדפן). השרת חייב לאמת את זה מול רשימה של מקורות הורים מוכרים ומורשים.

רשימת משימות לאימות

כדי לאמת את התשובה של אמצעי האימות בשרת, מבצעים את השלבים הבאים:

  1. מנתחים ומפענחים את החתימה collectedClientData מהתגובה של אמצעי האימות.
  2. מוודאים שהערך של type תואם לטקס (webauthn.get או webauthn.create).
  3. מאמתים את נוכחות המשתמש והחתימה שלו.
  4. אם הבקשה נועדה להגיע ממבנה iframe:
    • אכיפה של crossOrigin === true.
    • הגדרת אכיפה של התאמה בין topOrigin לבין רשימת המקורות המורשים של ההורה.

יצירת סשנים בצורה מאובטחת באמצעות postMessage()

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

תהליך עבודה מאובטח

כדי ליצור סשן מאובטח, פועלים לפי תהליך העבודה הבא:

  1. מוודאים שכתובת ה-URL של ה-iframe‏ src מכילה פרמטרים של שאילתה nonce ו-origin:
    • צריך להזין ערך אקראי במאפיין nonce. nonce משמש כאסימון לאימות אבטחה כדי לוודא שאסימון האימות שהתקבל מ-iframe תואם באופן לגיטימי לסשן הספציפי שהופעל על ידי דף האב.
    • משתמשים בדומיין של מסגרת ההורה בשביל origin. פרמטר origin מציין את המוצא של דף ההורה, וכך מאפשר ל-iframe לזהות בצורה מאובטחת את ההקשר המורשה שבו הוא מוטמע.
  2. ה-iframe משלים את האימות של WebAuthn עם השרת שלו.
  3. שרת ה-iframe מנפיק טוקן, כמו JWT, שכולל את nonce ומעביר אותו לדף ההורה.

    // Extract nonce and origin from the URL params
    const urlParams = new URLSearchParams(window.location.search);
    const nonce = urlParams.get('nonce');
    const origin = urlParams.get('origin');
    if (!nonce || !origin) {
      alert('Nonce or origin is missing in the URL');
      return;
    }
    
    // Create a JWT
    const response = await post('/createToken', { nonce, origin });
    const token = response.token;
    
    // Post the JWT to the parent frame
    window.parent.postMessage({ token }, origin);
    
  4. דף ההורה מקשיב לאירוע message, מאמת את המקור של השולח ומאמת את האסימון.

    window.addEventListener("message", (event) => {
      if (event.origin !== "https://embedded-auth.example.com") return;
      // Verify the received JWT
      const result = await post('/verifyIdToken', {
        token: event.data.token,
        origin: provider.origin,
      });
    });
    
  5. אם ה-JWT מאומת בהצלחה, דף ההורה שומר את הסשן.

השולח והמקבל חולקים את האחריות לאבטחה:

  • השולח (iframe): תמיד צריך לציין מקור יעד מדויק כששולחים הודעות (אף פעם לא להשתמש ב-"*").
  • הנמען (ההורה): תמיד צריך לאמת את event.origin כשמקבלים הודעות כדי למנוע זיוף מקור.

סיכום

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

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