Chrome 80 cookie sameSite none 兼容方案

背景

Chrome80 之后会启用 SameSite 默认为 Lax ,限制三方cookie的访问

SameSite

SameSite 是用来防止CSRF攻击和用户追踪。

支持如下三个配置:

Lax

默认 Lax 大多数情况也是不发送第三方 Cookie,但是导航到目标网址的 Get 请求除外。

1
Set-Cookie: CookieName=CookieValue; SameSite=Lax;

导航到目标网址的 GET 请求,只包括三种情况:链接,预加载请求,GET 表单。详见下表。

请求类型 示例 正常情况 Lax
链接 <a href="\.\.\."></a> 发送 Cookie 发送 Cookie
预加载 <link rel="prerender" href="..."/> 发送 Cookie 发送 Cookie
GET 表单 <form method="GET" action="..."> 发送 Cookie 发送 Cookie
POST 表单 <form method="POST" action="..."> 发送 Cookie 不发送
iframe <iframe src="..."></iframe> 发送 Cookie 不发送
AJAX $.get("...") 发送 Cookie 不发送
Image <img src="..."> 发送 Cookie 不发送

Strict

Strict 最为严格,完全禁止第三方 Cookie,跨站点时,任何情况下都不会发送 Cookie。只有当前网页的 URL 与请求目标一致,才会带上 Cookie。

1
Set-Cookie: CookieName=CookieValue; SameSite=Strict;

这个规则过于严格,可能造成非常不好的用户体验。比如,当前网页有一个 GitHub 链接,用户点击跳转就不会带有 GitHub 的 Cookie,跳转过去总是未登陆状态。

None

None 就是再回到之前不限制的样子,不过前提是必须同时设置Secure属性(Cookie 只能通过 HTTPS 协议发送),否则无效。

1
Set-Cookie: widget_session=abc123; SameSite=None; Secure

应对

理想是很好的,可以直接杜绝掉CSRF所带来的风险,但是对于自己原本使用三方cookie的场景也会被误伤

当站点的主域和api接口使用不同域的时候,就只能通过设置 None 来关闭 SameSite,不过在设置 SameSite 时部分浏览器存在兼容问题,导致整条cookie无法写入。

兼容方案

同一cookie重复设置

写入重复的 setCookie 头,区别只是否包含 SameSite,注意不带 SameSite 的先在前。

1
2
set-cookie: web_session=xxxxxxx; expires=Thu, 27-Aug-2020 12:13:09 GMT; Max-Age=7200; path=/; httponly
set-cookie: web_session=xxxxxxx; expires=Thu, 27-Aug-2020 12:13:09 GMT; Max-Age=7200; path=/; SameSite=None; secure; httponly

首先所有的浏览器都会支持第一条,然后支持第二条的一定是支持 SameSite 的浏览器

如上,类似于当年写 css 兼容 rgba 的时候,同时设置 rgbrgba,目前我们使用这种方案改动最小

使用token

对于原本使用 session 做登录认证替换为 token 来处理,这样客户端可以保存token到 LocalStorage ,由客户端发送请求的时候附带 tokenbody 或者 header 中。

这个方案需要服务端做较大的改造,要替换整个用户认证模块,如果新站可以考虑直接使用这种方式,异步请求就不要携带凭证 withCredentials: false

设置多个cookie

服务端写入一个 cookie 时需要同时写入 cookieName1SameSite: nullcookieName2 不设置SameSite

这样支持SameSite的浏览器会设置两个cookie,不支持的只会设置 cookieName2

新老版本都可以设置成功,取值的时候需要同时获取 cookieValue = Cookie.get('cookieName1') || Cookie.get('cookieName2')

服务端直接辨别兼容性

服务器不能像前端一样去尝试写入,只能靠 ua 分析了。

那要你的服务端足够厉害就可以,需要枚举足够多的 User-Agent 来识别浏览器是否支持 SameSite

不实用,除非你是 polyfill.io

参考

http://www.ruanyifeng.com/blog/2019/09/cookie-samesite.html