SameSite
相关含义和背景请参考之前的两篇文章:
本文主要介绍如何在各个浏览器上设置有效的 SameSite=None
。
为什么要设置 SameSite=None
?
Chrome, Firefox, Edge 和其他浏览器将根据 IETF 提案《渐进式更好的 Cookies》更改其默认行为,使得:
- 没有
SameSite
属性的 cookie 将会被视为SameSite=Lax
,这意味着默认行为是 cookie 仅限于 first-party 上下文中(关于 first-party 上下文的含义请参考这篇文章) - 跨站点使用的 cookie 必须指定
SameSite=None; Secure
来确保将其包含在第三方上下文中。
什么意思呢? 意思是默认情况下,跨站的 ajax 请求、img、iframe 等资源请求时候都不会带 cookie 了!
所以涉及到请求跨站资源需要携带 cookie 验证的网站必须解决这个问题。
那为什么不直接设置 SameSite=None
呢?
因为 SameSite
的 None
属性并不是一开始就提出来的,于是一些老版本浏览器并不会正确识别 SameSite=None
,浏览器对如何处理这种 Set-Cookie
标头存在不一致。
比如:
- Chrome 51 ~ Chrome 66 拒绝带有
SameSite=None
的 cookie。 - 12.13.2 之前版本的 UC 浏览器拒绝带有
SameSite=None
的 cookie。 - MacOS 10.14 上的 Safari 和嵌入式浏览器以及 iOS 12 上的所有浏览器会将标记为
SameSite=None
的 cookie 视为标记为SameSite=Strict
的 cookie。
可以看到,这些有问题的浏览器版本遇到 SameSite=None
后,要不然直接拒绝 cookie,要不然南辕北辙地将其视为 Strict
。为了避免这种情况的发生,需要采取一些方案以正确地升级 SameSite=None
。
升级方法
设置 SameSite=None 的前提是必须同时设置 Secure 属性(即 Cookie 只能通过 HTTPS 协议发送)
方法一:同时设置新旧两种 cookie
Set-cookie: 3pcookie=value; SameSite=None; Secure
Set-cookie: 3pcookie-legacy=value; Secure
这样,支持 SameSite=None
的浏览器将使用 SameSite
值设置 cookie 3pcookie=value
,而其他浏览器会将其忽略或将其视为 Strict
;但是两边都会设置 3pcookie-legacy=value
。
这样,在处理收到的 cookie
时,就可以检查是否存在 3pcookie
,如果不存在,则回退到 3pcookie-legacy
。
对于正确支持 None
的浏览器来说,自然可以正确发送相关 cookie
。而对于不能支持的浏览器来说,不设置 SameSite
属性的 cookie 它们将视为与新的规则效果一样。
示例如下(Node):
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 时都需要进行处理。
方法二:UA 检测
在发送 Set-Cookie
标头时,选择通过用户代理字符串进行检测
不兼容的客户端列表
ua 检测包: ua-parser-js
- 优点:只需要在设置 cookie 时进行一次处理
- 缺点:用户代理的嗅探本身可能无法捕获所有受影响的用户