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

שיתוף משאבים בין מקורות בצורה בטוחה

Mariko Kosaka

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

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

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

איך עובדת בקשה למשאב באינטרנט?

בקשה ותגובה
איור של בקשת לקוח ותגובת שרת.

דפדפן ושרת יכולים להחליף נתונים ברשת באמצעות פרוטוקול Hypertext Transfer Protocol ‏ (HTTP). פרוטוקול HTTP מגדיר את כללי התקשורת בין מגיש הבקשה למשיב, כולל המידע שנדרש כדי לקבל משאב.

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

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

דוגמה לכותרת בקשה

Accept: text/html
Cookie: Version=1

הכותרת הזו שוות ערך לאמירה 'אני רוצה לקבל HTML בתגובה'. הנה קובץ Cookie שיש לי".

דוגמה לכותרת תגובה

Content-Encoding: gzip
Cache-Control: no-store

הכותרת הזו שקולה לטענה 'הנתונים בתגובה הזו מקודדים באמצעות gzip'. אל תשמור את זה במטמון".

גוף

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

איך CORS עובד?

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

שלב 1: בקשה של לקוח (דפדפן)

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

שלב 2: תגובת השרת

כשהשרת רואה את הכותרת הזו ורוצה לאפשר גישה, הוא מוסיף כותרת Access-Control-Allow-Origin לתגובה ומציין את המקור של הבקשה (או * כדי לאפשר גישה מכל מקור).

שלב 3: הדפדפן מקבל תגובה

כשהדפדפן רואה את התשובה הזו עם כותרת Access-Control-Allow-Origin מתאימה, הוא משתף את נתוני התשובה עם האתר של הלקוח.

שיתוף פרטי כניסה עם CORS

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

בקשה

מוסיפים את credentials: 'include' לאפשרויות האחזור כמו בדוגמה הבאה. הוא כולל את קובץ ה-Cookie בבקשה באופן הבא:

fetch('https://example.com', {
  mode: 'cors',
  credentials: 'include'
})

תשובה

הערך של Access-Control-Allow-Origin חייב להיות מוגדר למקור ספציפי (ללא תו כללי באמצעות *), והערך של Access-Control-Allow-Credentials חייב להיות מוגדר ל-true.

HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Credentials: true

בקשות קדם-הפעלה לקריאות HTTP מורכבות

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

במפרט CORS מוגדרת בקשה מורכבת באופן הבא:

  • בקשה שמשתמשת בשיטות שאינן GET,‏ POST או HEAD.
  • בקשה שכוללת כותרות אחרות מלבד Accept, Accept-Language או Content-Language.
  • בקשה עם כותרת Content-Type שאינה application/x-www-form-urlencoded,‏ multipart/form-data או text/plain.

הדפדפנים יוצרים באופן אוטומטי את כל בקשות ה-preflight הנדרשות ושולחים אותן לפני הודעת הבקשה בפועל. בקשת קדם-הפעלה היא בקשת OPTIONS כמו בדוגמה הבאה:

OPTIONS /data HTTP/1.1
Origin: https://example.com
Access-Control-Request-Method: DELETE

בצד השרת, האפליקציה שמקבלת את הבקשה מגיבה לבקשת ה-preflight עם מידע על השיטות שהאפליקציה מקבלת מהמקור הזה:

HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: GET, DELETE, HEAD, OPTIONS

תגובת השרת יכולה לכלול גם כותרת Access-Control-Max-Age כדי לציין את משך הזמן בשניות שבו יש לשמור במטמון את תוצאות בדיקת הקדם-הפעלה. כך הלקוח יכול לשלוח כמה בקשות מורכבות בלי לחזור על בקשת הקדם-הפעלה.