Photo by Mohammad Rahmani on Unsplash
Bắt đầu từ phiên bản 84, Chrome mặc định thuộc tính SameSite của Cookie là Lax. Các dịch vụ sử dụng Third-party cookies có thể bị ảnh hưởng nếu không thiết lập SameSite đúng cách.
Tổng quan
Cookies là cơ chế được sử dụng trong các dịch vụ web để lưu trữ trạng thái, thường được dùng để duy trì phiên đăng nhập, giỏ hàng, theo dõi quảng cáo, v.v. Tuy nhiên, việc sử dụng rộng rãi Cookies cũng mang lại những lo ngại về quyền riêng tư và bảo mật, và SameSite đã được giới thiệu để giải quyết các vấn đề này.
First-Party and Third-Party
Dựa vào nguồn gốc của Cookie (Set-Cookie), mỗi Cookie có một Domain riêng. Khi xem xét URL hiện tại trong trình duyệt của người dùng, nếu Domain của Cookie khớp với URL hiện tại, đó là First-Party; ngược lại, đó là Third-Party.
Third-party
Ví dụ, khi duyệt trang web a.com, một yêu cầu (request) được gửi đến third-party.com và nhận được một Cookie từ third-party.com. Vì trình duyệt tự động gửi kèm các Cookie có cùng Domain trong các yêu cầu, nên nếu sau đó bạn duyệt một trang web khác như b.com và nó cũng gửi yêu cầu đến third-party.com, máy chủ sẽ nhận được Cookie. Đối với hai trang web này, Cookie của third-party.com là Third-party.
First-party
Nếu bạn duyệt một trang web khớp với Domain third-party.com, Cookie cũng sẽ được gửi đi. Trong trường hợp này, Cookie này được gọi là First-party.
Same-Origin and Same-Site
Ví dụ trước đã đề cập đến việc sử dụng Domain để xác định loại Cookie, nhưng cách nói chính xác hơn là xác định xem Site có giống nhau hay không. Điều này có liên quan đến Same-origin thường thấy không?

Origin
Origin bao gồm Scheme, Host và Port. Phương pháp xác định rất đơn giản: nếu Scheme, Host và Port của hai URL đều giống nhau, chúng là Same-origin; ngược lại, chúng là Cross-origin.
Site
Việc xác định Same-Site liên quan đến Effective top-level domains (eTLDs). Tất cả các eTLD được định nghĩa trong Public Suffix List, và một Site bao gồm một eTLD cộng với một tiền tố.
Ví dụ:
github.io tồn tại trong Public Suffix List. Thêm một tiền tố (ví dụ: a.github.io) sẽ tạo thành một Site. Do đó, a.github.io và b.github.io là hai Site khác nhau (Cross-site).
example.com không tồn tại trong Public Suffix List, nhưng .com thì có, vì vậy example.com là một Site, và a.example.com và b.example.com là cùng một Site (Same-site).
Lưu ý rằng Site không bao gồm Port, vì vậy ngay cả khi Port khác nhau, chúng vẫn có thể là Same-site.
Why SameSite?
Cơ chế “mọi Request đều mang theo cookie của Domain đó” cũng mang lại các vấn đề về bảo mật và các vấn đề khác, quan trọng nhất là Cross-site request forgery (CSRF).
CSRF
Giả sử người dùng đã đăng nhập vào example.com và nhận được Cookie. Khi người dùng duyệt trang web độc hại evil.com, JavaScript trong trang web đó có thể gửi một POST Request đến example.com/pay?amount=1000. Trình duyệt sẽ tự động gửi kèm Cookie của example.com, và người dùng vô tình thanh toán 1000 đô la. Máy chủ không thể xác định Request này đến từ đâu.
Hạn chế
Bản thân Cookie không thể được thiết lập để chỉ gửi trong môi trường First-party, vì vậy các Request sẽ mang theo Cookie trong bất kỳ môi trường nào. Máy chủ không thể xác định nguồn của Request và chỉ có thể phản hồi như bình thường, khiến Client lãng phí băng thông gửi các Cookie vô dụng.
Giải pháp
Với thuộc tính SameSite, chúng ta có thể thiết lập riêng các điều kiện gửi Cookie trong các môi trường khác nhau.
SameSite
Thuộc tính SameSite có ba giá trị. Đặt nó thành Strict hoặc Lax có thể hạn chế Cookie chỉ được gửi trong các yêu cầu Same-Site. Nếu để trống, hành vi phụ thuộc vào trình duyệt; đối với Chrome, mặc định là Lax.
Strict
Cookie chỉ được gửi trong môi trường First-party. Tuy nhiên, có một vấn đề: giả sử người dùng thấy một liên kết bài đăng Facebook trên example.com (giả sử là fb.com). Ngay cả khi người dùng đã đăng nhập vào fb.com và có Cookie, việc nhấp vào liên kết sẽ không gửi Cookie vì hai trang web là Cross-site, vì vậy họ sẽ chỉ thấy trang đăng nhập.
Do đó, Strict phù hợp cho các hành động nhạy cảm, chẳng hạn như xóa bài đăng, thanh toán, v.v.
Lax
Để giải quyết các hạn chế quá nghiêm ngặt của Strict, Lax cho phép gửi Cookie ngay cả trong các tình huống Cross-site trong các trường hợp sau:
- Nhập URL vào thanh địa chỉ
- Nhấp vào liên kết
<a href="..."> - Gửi biểu mẫu
<form method="GET"> - Prerendering
<link rel="prerender" href="...">
Các trường hợp này có hai điểm chung: chúng đều là các yêu cầu GET và đều kích hoạt Top-level Navigation. Điều này tránh được vấn đề Strict yêu cầu đăng nhập lại mỗi lần và cũng ngăn chặn việc vô tình gửi Cookie khi duyệt các trang web khác.
Lax + POST
Tuy nhiên, để tránh phá vỡ một số luồng đăng nhập hiện có, Chrome hiện tại đã nới lỏng hạn chế một chút cho SameSite=Lax, cho phép các nhà phát triển có thêm thời gian để thích nghi.
Trong vòng hai phút kể từ khi Cookie được thiết lập, bất kể Request Method là gì, miễn là nó kích hoạt điều hướng trang cấp cao nhất (top-level page navigation), Cookie sẽ được gửi. Điều này có nghĩa là nếu trình duyệt chuyển trang, ví dụ như gửi biểu mẫu <form method="POST">.
Để biết chi tiết, vui lòng xem chủ đề về Lax + POST.
None
Để gửi Third-party cookie, bạn phải thiết lập SameSite=None; Secure. Đúng vậy, từ giờ trở đi, nếu bạn muốn gửi Third-party cookie trong môi trường thử nghiệm, hãy chuẩn bị https://localhost.
Ngoài ra, việc gửi Cross-Origin Requests qua XHR/Fetch yêu cầu thiết lập withCredentials: true để gửi Cookie và làm cho Set-Cookie trong Response header có hiệu lực. Máy chủ cũng phải thiết lập Access-Control-Allow-Credentials: true trong Response header để JavaScript có thể truy cập nội dung Response.
Trình duyệt không hỗ trợ
Không phải tất cả các trình duyệt đều đã hỗ trợ các quy tắc SameSite mới nhất, vì vậy có thể thêm một số giải pháp tạm thời (Workaround) trên Máy chủ để hỗ trợ nhiều trình duyệt:
Thiết lập cả hai Cookie
Phương pháp này có thể giải quyết vấn đề cho hầu hết các trình duyệt, nhưng nhược điểm là sẽ có hai bản sao của Cookie:
Set-cookie: name=value; SameSite=None; Secure
Set-cookie: name-legacy=value; Secure
Mã phía máy chủ:
if (req.cookies['name']) {
// Sử dụng cái mới nếu có
cookieVal = req.cookies['name'];
} else if (req.cookies['name-legacy']) {
// Nếu không thì sử dụng cái cũ
cookieVal = req.cookies['name-legacy'];
}
User Agent
Xác định trình duyệt bằng cách sử dụng User agent của Request để quyết định nội dung của Set-Cookie. Phương pháp này chỉ yêu cầu sửa đổi mã thiết lập Cookie mà không thay đổi phần Parsing. Tuy nhiên, phương pháp đánh giá này có nhiều biến số hơn và dễ dẫn đến việc thiết lập sai Cookie.
Xem lại
- Cookie không có thuộc tính SameSite được thiết lập sẽ mặc định là
SameSite=Laxvàkhông thể gửi đượctrong môi trường Cross-site. - Để gửi Cookie trong Cross-site, bạn cần thiết lập
SameSite=None; Secure. - Bạn có thể sử dụng SameSite sandbox để kiểm tra xem trình duyệt hiện tại của bạn có tuân thủ các quy tắc SameSite mới nhất hay không.