Chrome 下 SameSite 为空时对跨站表单提交行为的处理策略

本文编写于 2020-11-2,只讨论 Chrome 及 Chromium 内核浏览器。且浏览器的安全策略会有更新,因此在参考该文章时请注意时效性。

关于 SameSite

Chrome 51 开始,浏览器的 Cookie 新增了一个 SameSite 属性,用来防止 CSRF 攻击和用户追踪。SameSite 的值分为三个等级:Strict、Lax、None,不同的等级对于 第三方 Cookie 有不同的限制,其中 Strict 和 None 比较简单,Strict 等级下完全禁止第三方 Cookie,None 等级下完全放开第三方 Cookie。

对于 Lax 等级下,不同的行为具有不同的结果,大致如下:

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

可能考虑到大部分厂商、机构一直没有很好的使用 SameSite 属性,作为行业领导者甚至是标准制定者,从 Chrome 80 开始,Chrome 开始将 SameSite 的默认值从 None 修改为 Lax。

背景

有同事反馈在第三方域下 POST 表单到公司域的时候,会出现一个诡异的现象,刚开始一切正常,在大概 2 分钟后,POST 数据携带的 Cookie 丢失,可能是部分丢失,也可能是全部丢失。Chrome 和 Edge(Chromium 内核)有问题,Firefox 无此异常。重点怀疑和 Chrome 下 SameSite 属性有关,但是无法解释为什么刚开始可以携带 Cookie。因为涉及到的业务较复杂,所以打算简化业务场景去做测试。

测试准备

  • 使用 https://sub0.example-a.com/a 作为 set-cookie 的页面,Cookie SameSite 类型包括四种:Strict、Lax、None、空。
  • 分别在 sub1.example-a.com 域和 A 域(暂且用 A 表示第三方域名)下 POST 表单到 https://sub0.example-a.com 查看客户端发送的 Cookie。

测试过程

  1. 访问 https://sub0.example-a.com/a 获取 Cookie。
  2. 在 https://sub1.example-a.com 的某个页面 POST 表单到 https://sub0.example-a.com,在任何情况下都可以携带所有 sub0.example-a.com 域下的 Cookie(因为根据 Cookie 同站规则判断都属于 example-a.com)。
  3. 两分钟内在 A 域下 POST 表单到 https://sub0.example-a.com,SameSite=Strict 的 Cookie 在任何情况下都不能携带,其他的都能携带。
  4. 两分钟之后,在 A 域下 POST 表单到 https://sub0.example-a.com ,只能携带 SameSite=None 的Cookie。
  5. 重复步骤 1
  6. 马上在 A 域下 POST 表单到 https://sub0.example-a.com ,只能携带 SameSite=None 的 Cookie。
  7. 修改 https://sub0.example-a.com/a 的页面逻辑: 改变 set-cookie 的 value,然后访问 https://sub0.example-a.com/a 获取新 Cookie。
  8. 马上在 A 域下 POST 表单到 https://sub0.example-a.com ,能携带 SameSite 为 None 或者空的 Cookie。
  9. 过了大概两分钟之后,在三方域下 POST 表单到 https://sub0.example-a.com ,只能携带 SameSite=None 的Cookie。

测试结论

根据测试过程和结果可以看到,Cookie SameSite 为空的时候确实存在有时效性的现象,在响应头获取新 Cookie首次获取该 Cookie 或者 Cookie 值有更新的两分钟内,跨站请求是被允许携带 Cookie 的,两分钟后该 Cookie 将会完全遵守 Lax 策略。

后来查阅资料,在 Chrome Platform Status 上得到了证实:

Note: Chrome will make an exception for cookies set without a SameSite attribute less than 2 minutes ago. Such cookies will also be sent with non-idempotent (e.g. POST) top-level cross-site requests despite normal SameSite=Lax cookies requiring top-level cross-site requests to have a safe (e.g. GET) HTTP method. Support for this intervention ("Lax + POST") will be removed in the future.

Chrome 在近段时间的一些行为略显激进,比如隐藏地址栏的协议、域名的 www 前缀,不过对于 SameSite 默认值的修改我是赞同的,这个行为在一定程度上能缓解 CSRF 的危害。

说到最后,我想说我最近将主力浏览器从 Chrome 换到了 Edge,Chrome 的资源占用是我无法忍受的,同是 Chromium 内核,相比来说 Edge 就做的很好,不过感觉这也是很多产品做大之后的通病吧。