本文编写于 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。
测试过程
- 访问 https://sub0.example-a.com/a 获取 Cookie。
- 在 https://sub1.example-a.com 的某个页面 POST 表单到 https://sub0.example-a.com,在任何情况下都可以携带所有 sub0.example-a.com 域下的 Cookie(因为根据 Cookie 同站规则判断都属于 example-a.com)。
- 两分钟内在 A 域下 POST 表单到 https://sub0.example-a.com,SameSite=Strict 的 Cookie 在任何情况下都不能携带,其他的都能携带。
- 两分钟之后,在 A 域下 POST 表单到 https://sub0.example-a.com ,只能携带 SameSite=None 的Cookie。
- 重复步骤 1
- 马上在 A 域下 POST 表单到 https://sub0.example-a.com ,只能携带 SameSite=None 的 Cookie。
- 修改 https://sub0.example-a.com/a 的页面逻辑: 改变 set-cookie 的 value,然后访问 https://sub0.example-a.com/a 获取新 Cookie。
- 马上在 A 域下 POST 表单到 https://sub0.example-a.com ,能携带 SameSite 为 None 或者空的 Cookie。
- 过了大概两分钟之后,在三方域下 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 就做的很好,不过感觉这也是很多产品做大之后的通病吧。