למה צריך "מבודד ממקורות שונים" כדי להשתמש בתכונות מתקדמות

למה צריך בידוד בין מקורות כדי להשתמש בתכונות מתקדמות כמו SharedArrayBuffer, ‏ performance.measureUserAgentSpecificMemory() וטיימר ברזולוציה גבוהה עם דיוק משופר.

מבוא

במאמר הפיכת האתר ל'מבודד בין מקורות' באמצעות COOP ו-COEP הסברנו איך להעביר את האתר למצב 'מבודד בין מקורות' באמצעות COOP ו-COEP. זהו מאמר נלווה שמסביר למה נדרש בידוד בין מקורות כדי להפעיל תכונות חזקות בדפדפן.

רקע

האינטרנט מבוסס על מדיניות המקור הזהה: תכונת אבטחה שמגבילה את האופן שבו מסמכים וסקריפטים יכולים לקיים אינטראקציה עם משאבים ממקור אחר. העיקרון הזה מגביל את הדרכים שבהן אתרים יכולים לגשת למשאבים ממקורות שונים. לדוגמה, למסמך מ-https://a.example אין גישה לנתונים שמתארחים ב-https://b.example.

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

  • הטמעת iframes ממקורות שונים
  • לכלול משאבים ממקורות שונים, כמו תמונות או סקריפטים
  • פתיחת חלונות קופצים ממקורות שונים באמצעות הפניה ל-DOM

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

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

כל ההחלטות האלה לגבי מדיניות מתקבלות בתוך קבוצת הקשר גלישה.

קבוצת הקשר של גלישה

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

כל זה השתנה עם Spectre, שעלול לאפשר קריאה של כל נתון שנטען לאותה קבוצת הקשר גלישה כמו הקוד שלכם. על ידי מדידת משך הזמן של פעולות מסוימות, תוקפים יכולים לנחש את התוכן של מטמון המעבד, וכך את התוכן של זיכרון התהליך. התקפות תזמון כאלה אפשריות באמצעות שעונים ברמת פירוט נמוכה שנמצאים בפלטפורמה, אבל אפשר להאיץ אותן באמצעות שעונים ברמת פירוט גבוהה, גם מפורשים (כמו performance.now()) וגם משתמעים (כמו SharedArrayBuffer). אם evil.com מטמיע תמונה ממקורות שונים, הוא יכול להשתמש בהתקפת Spectre כדי לקרוא את נתוני הפיקסלים שלה, וכתוצאה מכך אמצעי ההגנה שמסתמכים על 'חוסר שקיפות' לא יעילים.

Spectr

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

במצב של בידוד בין מקורות, האתר המבקש נחשב פחות מסוכן, וכך אפשר להשתמש בתכונות חזקות כמו SharedArrayBuffer,‏ performance.measureUserAgentSpecificMemory() ושעונים ברזולוציה גבוהה עם דיוק גבוה יותר, שיכולים לשמש להתקפות כמו Spectre. הוא גם מונע שינוי של document.domain.

מדיניות הטמעה ממקורות שונים

מדיניות להטמעה במקורות שונים (COEP) מונעת טעינת משאבים ממקורות שונים שלא מעניקים הרשאה מפורשת למסמך (באמצעות CORP או CORS). בעזרת התכונה הזו אפשר להצהיר שמסמך לא יכול לטעון משאבים כאלה.

איך פועלת תוכנית COEP

כדי להפעיל את המדיניות הזו, צריך לצרף למסמך את כותרת ה-HTTP הבאה:

Cross-Origin-Embedder-Policy: require-corp

מילת המפתח require-corp היא הערך היחיד שאפשר להשתמש בו עבור COEP. כך אפשר לאכוף את המדיניות שלפיה המסמך יכול לטעון רק משאבים מאותו מקור, או משאבים שסומנו במפורש כאפשריים לטעינה ממקור אחר.

כדי שאפשר יהיה לטעון משאבים ממקור אחר, הם צריכים לתמוך ב-Cross Origin Resource Sharing‏ (CORS) או ב-Cross Origin Resource Policy‏ (CORP).

שיתוף משאבים בין מקורות (CORS)

אם משאב ממקורות שונים תומך בשיתוף משאבים בין מקורות (CORS), אפשר להשתמש במאפיין crossorigin כדי לטעון אותו לדף האינטרנט בלי שהוא ייחסם על ידי COEP.

<img src="https://third-party.example.com/image.jpg" crossorigin>

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

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

מדיניות משאבים ממקורות שונים (CORS)

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

לכותרת Cross-Origin-Resource-Policy יש שלושה ערכים אפשריים:

Cross-Origin-Resource-Policy: same-site

אפשר לטעון משאבים שמסומנים ב-same-site רק מאותו אתר.

Cross-Origin-Resource-Policy: same-origin

אפשר לטעון משאבים שמסומנים ב-same-origin רק מאותו מקור.

Cross-Origin-Resource-Policy: cross-origin

כל אתר יכול לטעון משאבים שמסומנים ב-cross-origin. (הערך הזה נוסף למפרט CORP יחד עם COEP).

מדיניות פותחן מרובות מקורות

מדיניות פותח מקור חוצה (COOP) מאפשרת להבטיח שחלון ברמה העליונה מבודד ממסמכים אחרים על ידי הכנסת המסמכים האלה לקבוצה אחרת של הקשרי גלישה, כך שלא תהיה להם אינטראקציה ישירה עם החלון ברמה העליונה. לדוגמה, אם מסמך עם COOP פותח חלון קופץ, הערך של המאפיין window.opener יהיה null. בנוסף, המאפיין .closed של ההפניה של הפותח אליו יחזיר את הערך true.

COOP

לכותרת Cross-Origin-Opener-Policy יש שלושה ערכים אפשריים:

Cross-Origin-Opener-Policy: same-origin

מסמכים שמסומנים ב-same-origin יכולים לשתף את אותה קבוצת הקשר של גלישה עם מסמכים מאותו מקור שגם הם מסומנים ב-same-origin באופן מפורש.

COOP

Cross-Origin-Opener-Policy: same-origin-allow-popups

במסמך ברמה העליונה עם same-origin-allow-popups נשמרות הפניות לכל חלונות הקופץ שלו שלא מגדירים COOP או שמבטלים את ההסכמה לניתוק על ידי הגדרת ערך COOP של unsafe-none.

COOP

Cross-Origin-Opener-Policy: unsafe-none

unsafe-none היא ברירת המחדל ומאפשרת להוסיף את המסמך לקבוצת ההקשר של הגלישה של הכלי שפתח אותו, אלא אם לכלי עצמו יש ערך COOP של same-origin.

סיכום

אם אתם רוצים ליהנות מגישה מובטחת לתכונות מתקדמות כמו SharedArrayBuffer,‏ performance.measureUserAgentSpecificMemory() או שעונים עם רזולוציה גבוהה עם דיוק גבוה יותר, חשוב לזכור שבמסמך צריך להשתמש גם ב-COEP עם הערך require-corp וגם ב-COOP עם הערך same-origin. ללא אחת מהאפשרויות האלה, הדפדפן לא יוכל להבטיח בידוד מספיק כדי להפעיל את התכונות החזקות האלה בצורה בטוחה. כדי לבדוק את המצב של הדף, אפשר לבדוק אם הפונקציה self.crossOriginIsolated מחזירה את הערך true.

במאמר איך מבודדים את האתר מ-origin שונים באמצעות COOP ו-COEP מוסבר איך מטמיעים את התכונה הזו.

משאבים