สูตรคุกกี้ SameSite

Chrome, Firefox, Edge และเบราว์เซอร์อื่นๆ กำลังเปลี่ยนลักษณะการทำงานเริ่มต้นให้สอดคล้องกับข้อเสนอของ IETF เกี่ยวกับคุกกี้ที่ดีขึ้นเรื่อยๆ ดังนี้

  • ระบบจะถือว่าคุกกี้ที่ไม่มีแอตทริบิวต์ SameSite เป็น SameSite=Lax ซึ่งหมายความว่าลักษณะการทำงานเริ่มต้นคือการจํากัดคุกกี้ให้แสดงในบริบทของบุคคลที่หนึ่งเท่านั้น
  • คุกกี้สำหรับการใช้งานข้ามเว็บไซต์ต้องระบุ SameSite=None; Secure เพื่อเปิดใช้การรวมในบริบทของบุคคลที่สาม

คุณควรอัปเดตแอตทริบิวต์สําหรับคุกกี้ของบุคคลที่สามเพื่อไม่ให้ถูกบล็อกในอนาคต หากยังไม่ได้ดำเนินการ

การรองรับเบราว์เซอร์

  • Chrome: 51.
  • Edge: 16.
  • Firefox: 60
  • Safari: 13.

แหล่งที่มา

กรณีการใช้งานสําหรับคุกกี้ข้ามเว็บไซต์หรือคุกกี้ของบุคคลที่สาม

มีกรณีการใช้งานและรูปแบบที่พบได้ทั่วไปจำนวนมากที่จำเป็นต้องส่งคุกกี้ในบริบทของบุคคลที่สาม หากคุณระบุหรือขึ้นอยู่กับกรณีการใช้งานอย่างใดอย่างหนึ่งเหล่านี้ ให้ตรวจสอบว่าคุณหรือผู้ให้บริการกำลังอัปเดตคุกกี้ของตนเพื่อให้บริการทำงานได้อย่างถูกต้อง

เนื้อหาภายใน <iframe>

เนื้อหาจากเว็บไซต์อื่นที่แสดงใน <iframe> อยู่ในบริบทของบุคคลที่สาม กรณีการใช้งานมาตรฐานมีดังนี้

  • เนื้อหาที่ฝังซึ่งแชร์จากเว็บไซต์อื่น เช่น วิดีโอ แผนที่ ตัวอย่างโค้ด และโพสต์บนโซเชียลเน็ตเวิร์ก
  • วิดเจ็ตจากบริการภายนอก เช่น การชำระเงิน ปฏิทิน การจอง และฟีเจอร์การจอง
  • วิดเจ็ต เช่น ปุ่มโซเชียลหรือบริการป้องกันการประพฤติมิชอบที่สร้างความชัดเจนน้อยลง<iframes>

คุกกี้อาจใช้เพื่อคงสถานะเซสชัน จัดเก็บค่ากําหนดทั่วไป เปิดใช้สถิติ หรือปรับเปลี่ยนเนื้อหาในแบบของคุณสําหรับผู้ใช้ที่มีบัญชีอยู่แล้ว

แผนภาพแสดงหน้าต่างเบราว์เซอร์ซึ่ง URL ของเนื้อหาที่ฝังไม่ตรงกับ URL ของหน้าเว็บ
หากเนื้อหาที่ฝังไม่ได้มาจากเว็บไซต์เดียวกับบริบทการท่องเว็บระดับบนสุด แสดงว่าเป็นเนื้อหาของบุคคลที่สาม

เนื่องจากเว็บเป็นแพลตฟอร์มที่ประกอบกันได้อยู่แล้ว <iframes> จึงใช้เพื่อฝังเนื้อหาที่ดูในบริบทระดับบนสุดหรือบริบทของบุคคลที่หนึ่งด้วย คุกกี้ที่เว็บไซต์แสดงใน iframe จะใช้เป็นคุกกี้ของบุคคลที่สาม หากคุณสร้างเว็บไซต์ที่ต้องการให้เว็บไซต์อื่นๆ ฝังและต้องการใช้คุกกี้เพื่อให้เว็บไซต์ทำงานได้ คุณจะต้องตรวจสอบว่าเว็บไซต์เหล่านั้นมีการทำเครื่องหมายสำหรับการใช้งานข้ามเว็บไซต์ หรือคุณมีวิธีเปลี่ยนเส้นทางอย่างราบรื่นหากไม่มีคุกกี้

คำขอ "ไม่ปลอดภัย" ในเว็บไซต์ต่างๆ

"ไม่ปลอดภัย" อาจฟังดูน่ากังวล แต่คำนี้หมายถึงคำขอที่อาจมีเจตนาเปลี่ยนแปลงสถานะ แต่สำหรับในเว็บ จะเป็นคำขอ POST เป็นหลัก ระบบจะส่งคุกกี้ที่มีการทำเครื่องหมายเป็น SameSite=Lax ในการนำทางระดับบนสุดที่ปลอดภัย เช่น การคลิกลิงก์เพื่อไปยังเว็บไซต์อื่น อย่างไรก็ตาม การส่ง <form> ไปยังเว็บไซต์อื่นโดยใช้ POST นั้นจะไม่รวมคุกกี้

แผนภาพคําขอที่ย้ายจากหน้าหนึ่งไปยังอีกหน้าหนึ่ง
หากคำขอที่เข้ามาใช้วิธีการที่ "ปลอดภัย" หน้าเว็บจะส่งคุกกี้

รูปแบบนี้ใช้สำหรับเว็บไซต์ที่สามารถเปลี่ยนเส้นทางผู้ใช้ไปยังบริการระยะไกลเพื่อดำเนินการบางอย่างก่อนย้อนกลับได้ เช่น เปลี่ยนเส้นทางไปยังผู้ให้บริการข้อมูลประจำตัวบุคคลที่สาม ก่อนที่ผู้ใช้จะออกจากเว็บไซต์ ระบบจะตั้งค่าคุกกี้ที่มีโทเค็นแบบใช้ครั้งเดียว โดยคาดหวังว่าจะตรวจสอบโทเค็นนี้ได้ในคําขอที่ส่งกลับเพื่อลดการโจมตีการปลอมแปลงคําขอข้ามเว็บไซต์ (CSRF) หากคำขอที่ส่งกลับนั้นมาผ่าน POST คุณจะต้องทําเครื่องหมายคุกกี้เป็น SameSite=None; Secure

ทรัพยากรระยะไกล

ทรัพยากรระยะไกลในหน้าเว็บ เช่น จากแท็ก <img> หรือแท็ก <script> อาจใช้คุกกี้ที่ส่งไปพร้อมกับคําขอ กรณีการใช้งานที่พบได้ทั่วไป ได้แก่ พิกเซลการติดตามและการปรับเปลี่ยนเนื้อหาในแบบของคุณ

ซึ่งจะมีผลกับคําขอที่ส่งจาก JavaScript โดยใช้ fetch หรือ XMLHttpRequest ด้วย หากมีการเรียก fetch() ด้วยตัวเลือก credentials: 'include' คำขอเหล่านั้นมักจะมีคุกกี้ สําหรับ XMLHttpRequest คุกกี้ที่คาดไว้มักจะระบุด้วยค่า withCredentials ของ true คุกกี้เหล่านั้นต้องมีการทําเครื่องหมายอย่างเหมาะสมเพื่อให้รวมอยู่ในคําขอข้ามเว็บไซต์

เนื้อหาภายใน WebView

WebView ในแอปเฉพาะแพลตฟอร์มขับเคลื่อนโดยเบราว์เซอร์ นักพัฒนาแอปต้องทดสอบว่าข้อจำกัดหรือปัญหาที่ส่งผลกระทบต่อแอปของตนมีผลกับ WebView ของแอปด้วยหรือไม่

นอกจากนี้ Android ยังอนุญาตให้แอปเฉพาะแพลตฟอร์มตั้งค่าคุกกี้ได้โดยตรงโดยใช้ CookieManager API เช่นเดียวกับคุกกี้ที่ตั้งค่าโดยใช้ส่วนหัวหรือ JavaScript ให้พิจารณาใส่ SameSite=None; Secure หากมีจุดประสงค์เพื่อการใช้งานแบบข้ามเว็บไซต์

วิธีใช้ SameSite วันนี้เลย

ทำเครื่องหมายคุกกี้ที่จำเป็นเฉพาะในบริบทของบุคคลที่หนึ่งเป็น SameSite=Lax หรือ SameSite=Strict โดยขึ้นอยู่กับความต้องการของคุณ หากคุณไม่ได้ทําเครื่องหมายคุกกี้เหล่านี้และอาศัยลักษณะการทํางานเริ่มต้นของเบราว์เซอร์เพื่อจัดการแทน คุกกี้อาจทํางานอย่างไม่สอดคล้องกันในเบราว์เซอร์ต่างๆ และอาจทริกเกอร์คําเตือนในคอนโซลสําหรับคุกกี้แต่ละรายการ

Set-Cookie: first_party_var=value; SameSite=Lax

อย่าลืมทำเครื่องหมายคุกกี้ที่จำเป็นในบริบทของบุคคลที่สามเป็น SameSite=None; Secure โดยต้องระบุแอตทริบิวต์ทั้ง 2 รายการ หากคุณระบุแค่ None โดยไม่ระบุ Secure ระบบจะปฏิเสธคุกกี้ หากต้องการอธิบายความแตกต่างในการใช้งานเบราว์เซอร์ คุณอาจต้องใช้กลยุทธ์การบรรเทาปัญหาที่อธิบายไว้ในส่วนจัดการไคลเอ็นต์ที่เข้ากันไม่ได้

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

จัดการไคลเอ็นต์ที่ทำงานร่วมกันไม่ได้

เนื่องจากการเปลี่ยนแปลงเหล่านี้เพื่อรวม None และลักษณะการทำงานเริ่มต้นที่อัปเดตยังค่อนข้างใหม่มาก เบราว์เซอร์ที่แตกต่างกันจึงจะจัดการกับการเปลี่ยนแปลงด้วยวิธีที่แตกต่างกัน คุณสามารถไปที่หน้าอัปเดตใน chromium.org เพื่อดูรายการปัญหาที่ทราบ แต่รายการนี้อาจไม่ครอบคลุมทั้งหมด

วิธีแก้ปัญหาที่เป็นไปได้อย่างหนึ่งคือการตั้งค่าคุกกี้แต่ละรายการทั้งในรูปแบบใหม่และแบบเก่า ดังนี้

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

เบราว์เซอร์ที่ใช้ลักษณะการทํางานแบบใหม่จะตั้งค่าคุกกี้ด้วยค่า SameSite เบราว์เซอร์ที่ไม่ได้ใช้ลักษณะการทำงานใหม่จะละเว้นค่าดังกล่าวและตั้งค่าคุกกี้ 3pcookie-legacy เมื่อประมวลผลคุกกี้ที่รวมไว้ เว็บไซต์ควรตรวจสอบว่ามีคุกกี้รูปแบบใหม่หรือไม่ก่อน แล้วจึงกลับไปใช้คุกกี้เดิมหากไม่พบคุกกี้ใหม่

ตัวอย่างต่อไปนี้แสดงวิธีทำใน Node.js โดยใช้เฟรมเวิร์ก Express และมิดเดิลแวร์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);

วิธีนี้ทำให้คุณต้องตั้งค่าคุกกี้ซ้ำซ้อนเพิ่มเติมและทำการเปลี่ยนแปลงทั้งในเวลาที่ตั้งค่าและอ่านคุกกี้ อย่างไรก็ตาม คุกกี้นี้ควรครอบคลุมเบราว์เซอร์ทั้งหมดโดยไม่คำนึงถึงลักษณะการทำงาน และคุกกี้ของบุคคลที่สามยังคงทำงานอยู่

โดยคุณจะตรวจหาไคลเอ็นต์โดยใช้สตริง User Agent เมื่อส่งส่วนหัว Set-Cookie แทนได้ โปรดดูรายการไคลเอ็นต์ที่เข้ากันไม่ได้ และใช้ไลบรารีการตรวจหา User Agent ที่เหมาะสมสําหรับแพลตฟอร์มของคุณ เช่น ไลบรารี ua-parser-js ใน Node.js วิธีนี้กําหนดให้คุณทำการเปลี่ยนแปลงเพียงรายการเดียว แต่การดักจับ User Agent อาจไม่ตรวจจับผู้ใช้ทั้งหมดที่ได้รับผลกระทบ

รองรับ SameSite=None ในภาษา ไลบรารี และเฟรมเวิร์ก

ภาษาและไลบรารีส่วนใหญ่รองรับแอตทริบิวต์ SameSite สําหรับคุกกี้ อย่างไรก็ตาม เนื่องจากการเพิ่ม SameSite=None เพิ่งเกิดขึ้นเมื่อไม่นานมานี้ คุณจึงอาจต้องปรับเปลี่ยนลักษณะการทํางานบางอย่างที่เป็นมาตรฐานในตอนนี้ ลักษณะการทำงานเหล่านี้มีการบันทึกไว้ในที่เก็บSameSiteตัวอย่างใน GitHub

การขอความช่วยเหลือ

คุกกี้มีการใช้งานในทุกที่บนเว็บ และทีมพัฒนาซอฟต์แวร์แทบจะไม่มีความรู้ที่สมบูรณ์เกี่ยวกับตําแหน่งที่เว็บไซต์ตั้งค่าและใช้คุกกี้ โดยเฉพาะใน Use Case แบบข้ามเว็บไซต์ เมื่อคุณพบปัญหา อาจเป็นครั้งแรก ที่ทุกคนพบเจอ ดังนั้น โปรดอย่าลังเลที่จะติดต่อเรา