מתכונים לקובצי cookie של SameSite

Chrome, Firefox, Edge ועוד ישנו את התנהגות ברירת המחדל שלהם, בהתאם להצעת ה-IETF, קובצי cookie טובים יותר באופן מצטבר. כך:

  • קובצי cookie בלי המאפיין SameSite יטופלו כ-SameSite=Lax, כלומר, התנהגות ברירת המחדל תהיה הגבלה של קובצי cookie בהקשרים של צד ראשון בלבד.
  • בקובצי cookie לשימוש באתרים שונים חובה לציין SameSite=None; Secure כדי לאפשר הכללה בהקשר של צד שלישי.

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

תמיכה בדפדפנים שונים

עיינו בקטע תאימות דפדפן בדף Set-Cookie של MDN.

תרחישים לדוגמה עבור קובצי cookie של אתרים שונים או של צדדים שלישיים

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

תוכן בתוך <iframe>

תוכן מאתר אחר שמוצג ב-<iframe> מוצג בהקשר של צד שלישי. הנה תרחישים לדוגמה לדוגמה:

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

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

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

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

בקשות "לא בטוחות" באתרים שונים

בעוד ש'לא בטוח' נשמע מעט מדאיג, מתייחס לכל בקשה שעשויה להיות מכוונת לשנות מצב. באינטרנט שכוללות בעיקר בקשות POST. קובצי cookie שמסומנים כ-SameSite=Lax יישלחו בניווטים בטוחים ברמה העליונה, למשל, לחיצה על קישור כדי לעבור לאתר אחר. עם זאת, משהו כמו שליחת <form> באמצעות POST לאתר אחר לא יכלול קובצי cookie.

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

הדפוס הזה משמש לאתרים שעשויים להפנות את המשתמש החוצה לשירות מרחוק כדי לבצע פעולה כלשהי לפני החזרה, למשל הפניה אוטומטית לספק זהויות של צד שלישי. לפני שהמשתמש עוזב את האתר, מוגדר קובץ Cookie שמכיל אסימון שימוש יחיד, על מנת שניתן יהיה לבדוק את האסימון בבקשה החוזרת, כדי לצמצם את ההתקפות של Cross Site Request Forgery (CSRF). אם הבקשה החוזרת מגיעה דרך POST, צריך לסמן את קובצי ה-cookie כ-SameSite=None; Secure.

משאבים מרוחקים

יכול להיות שכל משאב מרוחק בדף מסתמך על קובצי cookie שיישלחו עם בקשה, מתגי <img>, מתגי <script> וכו'. תרחישים נפוצים לדוגמה כוללים פיקסלים למעקב והתאמה אישית של תוכן.

הכלל הזה חל גם על בקשות שנשלחו מ-JavaScript על ידי fetch או XMLHttpRequest. אם מפעילים את fetch() עם האפשרות credentials: 'include', זה סימן טוב לכך שקובצי cookie צפויים להיות צפויים בעקבות הבקשות האלה. עבור XMLHttpRequest, צריך לחפש מופעים של הנכס withCredentials שמוגדר ל-true. זהו אינדיקציה טובה לכך שקובצי cookie צפויים להיות צפויים בבקשות האלה. כדי שקובצי ה-cookie האלה ייכללו בבקשות בין אתרים, צריך לסמן אותם כראוי.

תוכן ב-WebView

WebView באפליקציה ספציפית לפלטפורמה מופעל על ידי דפדפן, וצריך לבדוק אם אותן הגבלות או בעיות חלות. ב-Android, אם ה-WebView מופעל על ידי Chrome, ברירות המחדל החדשות לא יחולו באופן מיידי על Chrome 84. עם זאת, המטרה היא ליישם אותם בעתיד, ולכן כדאי עדיין לבדוק אותם ולהתכונן לקראתם. בנוסף, Android מאפשר לאפליקציות הספציפיות לפלטפורמה שלו להגדיר קובצי cookie ישירות באמצעות CookieManager API. בדומה לקובצי cookie שמוגדרים באמצעות כותרות או JavaScript, כדאי לכלול SameSite=None; Secure אם הם מיועדים לשימוש בכל האתרים.

איך ליישם את SameSite היום

לקובצי cookie שבהם הם נחוצים רק בהקשר של צד ראשון, רצוי לסמן אותם בתור SameSite=Lax או SameSite=Strict בהתאם לצרכים שלכם. אפשר גם לבחור לא לעשות דבר ולהתיר לדפדפן לאכוף את ברירת המחדל, אבל יש סיכון להתנהגות לא עקבית בין דפדפנים שונים ואזהרות פוטנציאליות במסוף לכל קובץ cookie.

Set-Cookie: first_party_var=value; SameSite=Lax

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

Set-Cookie: third_party_var=value; SameSite=None; Secure

טיפול בלקוחות לא תואמים

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

האפשרות הראשונה היא להגדיר גם את קובצי ה-cookie בסגנון החדש וגם את קובצי ה-cookie בסגנון ישן:

Set-cookie: 3pcookie=value; SameSite=None; Secure
Set-cookie: 3pcookie-legacy=value; Secure

דפדפנים שמיישמים את ההתנהגות החדשה יותר יגדירו את קובץ ה-cookie עם הערך SameSite, ודפדפנים אחרים עשויים להתעלם ממנו או להגדיר אותו בצורה שגויה. עם זאת, אותם דפדפנים יגדירו את קובץ ה-cookie של 3pcookie-legacy. במהלך העיבוד של קובצי cookie כלולים, האתר צריך קודם לבדוק אם קובץ ה-cookie החדש נמצא בסגנון החדש, ואם הוא לא נמצא, לחזור לגרסה הקודמת של קובץ ה-cookie.

הדוגמה הבאה ממחישה איך לעשות זאת ב-Node.js, באמצעות Express framework והתווכת שלו cookie-parser.

const express = require('express');
const cp = require('cookie-parser');
const app = express();
app.use(cp());

app.get('/set', (req, res) => {
  // Set the new style cookie
  res.cookie('3pcookie', 'value', { sameSite: 'none', secure: true });
  // And set the same value in the legacy cookie
  res.cookie('3pcookie-legacy', 'value', { secure: true });
  res.end();
});

app.get('/', (req, res) => {
  let cookieVal = null;

  if (req.cookies['3pcookie']) {
    // check the new style cookie first
    cookieVal = req.cookies['3pcookie'];
  } else if (req.cookies['3pcookie-legacy']) {
    // otherwise fall back to the legacy cookie
    cookieVal = req.cookies['3pcookie-legacy'];
  }

  res.end();
});

app.listen(process.env.PORT);

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

לחלופין, בנקודת שליחת הכותרת Set-Cookie, אפשר לבחור לזהות את הלקוח דרך המחרוזת של סוכן המשתמש. מומלץ לעיין ברשימת הלקוחות שאינם תואמים ולהשתמש בספרייה שמתאימה לפלטפורמה שלכם, למשל, ua-parser-js ב-Node.js. מומלץ למצוא ספרייה לטיפול בזיהוי סוכן המשתמש, מכיוון שסביר להניח שלא תרצו לכתוב את הביטויים הרגולריים האלה בעצמכם.

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

תמיכה עבור SameSite=None בשפות, בספריות ובמסגרות

רוב השפות והספריות תומכות במאפיין SameSite לקובצי cookie, אבל ההוספה של SameSite=None עדיין חדשה יחסית. פירוש הדבר הוא שייתכן שתצטרכו לעקוף חלק מההתנהגות הרגילה בשלב זה. הם מתועדים במאגר הדוגמאות של SameSite ב-GitHub.

קבלת עזרה

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