แอตทริบิวต์และ SameSite
ภาพรวมของ attribute cookie
หัวข้อที่มีชื่อว่า “ภาพรวมของ attribute cookie”Attribute ของ cookie ถูกเพิ่มหลังคู่ name=value คั่นด้วยเซมิโคลอน ช่วยควบคุมอายุ ขอบเขต ความปลอดภัยในการส่ง และพฤติกรรมข้ามเว็บไซต์
Set-Cookie: session=abc123; Max-Age=3600; Path=/; Secure; HttpOnly; SameSite=Strictมีเพียงคู่ name=value เท่านั้นที่จำเป็น ทุก attribute เป็นตัวเลือก แต่การละเว้น attribute ที่เกี่ยวข้องกับความปลอดภัย เช่น SameSite และ Secure จะทำให้ cookie เสี่ยงต่อการโจมตี
Expires และ Max-Age — การควบคุมอายุ
หัวข้อที่มีชื่อว่า “Expires และ Max-Age — การควบคุมอายุ”สอง attribute นี้ควบคุมว่า cookie จะเป็น session cookie หรือ persistent cookie
ไม่มี Expires/Max-Age → session cookie ที่ browser ลบทิ้งเมื่อ session แท็บ/หน้าต่างสิ้นสุด (พฤติกรรมการปิด browser แตกต่างกันตาม browser และการตั้งค่า “restore session”)
Set-Cookie: pref=darkExpires=<date> → persistent cookie ลบเมื่อถึงวันที่ UTC ที่กำหนด:
Set-Cookie: pref=dark; Expires=Thu, 01 Jan 2027 00:00:00 GMTMax-Age=<seconds> → persistent cookie ลบหลังจากนี้ตามจำนวนวินาที แนะนำให้ใช้แทน Expires เพราะเป็น relative และหลีกเลี่ยงปัญหา clock-skew:
Set-Cookie: pref=dark; Max-Age=86400การตั้ง Max-Age=0 (หรือค่าลบ) จะลบ cookie ทันที
Path — ขอบเขต URL
หัวข้อที่มีชื่อว่า “Path — ขอบเขต URL”Path จำกัดว่า request URL ใดที่ browser จะแนบ cookie ไปด้วย:
Set-Cookie: admin_token=xyz; Path=/adminbrowser จะส่ง cookie นี้เฉพาะ request ที่ path ขึ้นต้นด้วย /admin เท่านั้น Request ไปยัง / หรือ /app จะไม่รวม cookie นี้
ค่าเริ่มต้น: ถ้าไม่ระบุ browser จะใช้ path ของ URL ที่ตั้ง cookie (มักเป็น /)
Domain — ขอบเขต host
หัวข้อที่มีชื่อว่า “Domain — ขอบเขต host”Domain ควบคุมว่า hostname ใดจะได้รับ cookie:
Set-Cookie: pref=dark; Domain=.example.comจุดนำหน้า (.example.com) หมายความว่า cookie จะถูกส่งไปยัง example.com และ subdomain ทั้งหมด (api.example.com, www.example.com ฯลฯ)
ถ้าไม่ระบุ Domain cookie จะถูกส่งเฉพาะ host ที่ตั้งค่า cookie นั้นเท่านั้น (ไม่มี subdomain)
Secure — เฉพาะ HTTPS
หัวข้อที่มีชื่อว่า “Secure — เฉพาะ HTTPS”Secure สั่งให้ browser ส่ง cookie เฉพาะผ่านการเชื่อมต่อ HTTPS:
Set-Cookie: session=abc; Secureหากไม่มี Secure cookie จะถูกส่งผ่าน HTTP ธรรมดา ซึ่งอาจถูก intercept โดยผู้โจมตีบนเครือข่าย (man-in-the-middle) cookie ที่มีข้อมูลสำคัญทั้งหมดต้องมี Secure
HttpOnly — มองไม่เห็นจาก JavaScript
หัวข้อที่มีชื่อว่า “HttpOnly — มองไม่เห็นจาก JavaScript”HttpOnly คือหนึ่งใน attribute ด้านความปลอดภัยที่สำคัญที่สุด เพราะป้องกันไม่ให้ JavaScript อ่าน cookie ผ่าน document.cookie:
Set-Cookie: session=abc123; HttpOnly; Secure; SameSite=Strictด้วย HttpOnly แม้ว่าผู้โจมตีจะฉีด JavaScript อันตรายเข้ามาในหน้าเว็บ (XSS) script นั้นก็ไม่สามารถขโมย session cookie ได้ cookie ยังคงถูกส่งโดยอัตโนมัติพร้อม HTTP request — แค่ JavaScript ไม่สามารถอ่านหรือแก้ไขได้
cookie HttpOnly สามารถตั้งค่าได้โดย server เท่านั้นผ่าน Set-Cookie header document.cookie ฝั่ง client ไม่สามารถตั้ง HttpOnly cookies ได้
SameSite — การควบคุม cross-site request
หัวข้อที่มีชื่อว่า “SameSite — การควบคุม cross-site request”SameSite ควบคุมเมื่อใดที่ cookie จะถูกส่งใน cross-site request ช่วยป้องกัน CSRF (Cross-Site Request Forgery)
SameSite=Strict — cookie ถูกส่งเฉพาะ same-site request (การนำทางและ request ที่เกิดจากเว็บไซต์เอง) ไม่เคยส่งบน cross-site request:
Set-Cookie: session=abc; SameSite=Strictดีที่สุดสำหรับ session cookie — ป้องกัน CSRF สูงสุด
SameSite=Lax (ค่าเริ่มต้นใน browser สมัยใหม่) — cookie ถูกส่งบน same-site request และการนำทางระดับบนสุดจากเว็บไซต์อื่น (เช่น คลิกลิงก์ไปยังเว็บไซต์ของคุณจากอีเมล) แต่ไม่ส่งบน cross-site subresource request (รูปภาพ, iframe, fetch):
Set-Cookie: pref=dark; SameSite=Laxความสมดุลที่ดีสำหรับ cookie ส่วนใหญ่
SameSite=None; Secure — cookie ถูกส่งบน request ทั้งหมดรวมถึง cross-site ต้องใช้คู่กับ Secure ไม่เช่นนั้น browser จะปฏิเสธ จำเป็นสำหรับกรณีการใช้งาน cross-site ที่ถูกกฎหมาย (เช่น widget ฝังตัว, third-party authentication):
Set-Cookie: analytics_id=abc; SameSite=None; Secureคำแนะนำสำหรับ session cookie
หัวข้อที่มีชื่อว่า “คำแนะนำสำหรับ session cookie”สำหรับ cookie ที่ใช้ยืนยันตัวตนผู้ใช้หรืออนุญาตการกระทำ ให้ใช้ security attribute ทั้งสาม:
Set-Cookie: session=abc123; Max-Age=3600; Path=/; Secure; HttpOnly; SameSite=Strictการรวมนี้:
- ส่ง cookie เฉพาะผ่าน HTTPS (
Secure) - บล็อกการเข้าถึง JavaScript ป้องกันการขโมยผ่าน XSS (
HttpOnly) - ป้องกัน cookie ถูกส่งบน cross-site request บล็อก CSRF (
SameSite=Strict)
ข้อแลกเปลี่ยน
หัวข้อที่มีชื่อว่า “ข้อแลกเปลี่ยน”| ตัวเลือก | Benefit | Cost |
|---|---|---|
HttpOnly | ป้องกัน session token ถูกขโมยผ่าน XSS เพราะ JavaScript อ่าน cookie นั้นไม่ได้เลย | JavaScript ฝั่ง client อ่านหรืออัปเดตค่า cookie นั้นเองไม่ได้ ต้องพึ่ง server เท่านั้น |
SameSite=Strict | ป้องกัน CSRF ได้สูงสุดเพราะไม่ส่ง cookie บน cross-site request เลย | ทำลาย flow ที่ต้องพึ่ง cookie ตอนนำทางข้ามเว็บไซต์ เช่นคลิกลิงก์จากอีเมลแล้วต้องยัง login อยู่ |
SameSite=None; Secure | รองรับ use case cross-site ที่ถูกกฎหมาย เช่น widget ฝังตัวหรือ third-party auth | เปิดช่องให้ cookie ถูกส่งบน cross-site request ทุกกรณี เพิ่มพื้นที่เสี่ยงต่อ CSRF ถ้าไม่มีการป้องกันอื่นเสริม |
ข้อผิดพลาดที่พบบ่อย
หัวข้อที่มีชื่อว่า “ข้อผิดพลาดที่พบบ่อย”- ไม่ระบุ
SameSite/Secureเลย — cookie จะเสี่ยงถูกส่งผ่าน HTTP ธรรมดา (ไม่มีSecure) และเสี่ยงต่อ CSRF มากขึ้นถ้า browser หรือ config เก่าไม่บังคับค่า default ที่ปลอดภัย - ตั้ง
SameSite=Noneโดยไม่มีSecureคู่กัน — browser สมัยใหม่จะปฏิเสธ cookie นั้นทั้งชิ้นทันที ไม่ใช่แค่เตือน - เก็บ auth token ไว้ใน cookie ที่ไม่ใช่
HttpOnly— ทำลายจุดประสงค์หลักของการใช้ cookie เพื่อความปลอดภัย เพราะ script ที่ถูกฉีดเข้ามาผ่าน XSS จะอ่าน token นั้นออกไปได้ทันที
💡 ตัวอย่างจากของจริง
Session-based authentication — บริการ login เกือบทั้งหมดตั้งค่า session cookie ด้วย
HttpOnly; Secure; SameSite=Strictเพื่อให้ server ยืนยันตัวตนได้โดยที่ JavaScript แตะต้อง token ไม่ได้เลยThird-party ad/analytics cookie — ผู้ให้บริการโฆษณาที่ต้อง track ผู้ใช้ข้ามเว็บไซต์ผ่าน iframe ต้องใช้
SameSite=None; Secureเพราะเป็น cross-site request โดยธรรมชาติ