layout: post title: SameSite Cookies 解读
SameSite 属性是 HTTP 响应头 Set-Cookie
的属性之一,允许服务端控制该 Cookie 是否仅限于同站。
同站(跨站)是与常见的同域(跨域)相似的概念,下面是两者的区别。
域(Origin)由协议(Scheme)、主机名(Hostname)和端口(Port)组成。其中任何一个不同都会被认为是跨域。
顶级域名(Top-level domains)(TLDs)是如 .com
等的一系列域名列表。
在大部分场景下,站(Site)的定义是 TLDs+1,如 .com
的下一级,如 github.com
。
但 Github 也会为不同的开发者提供不同的 github.io
域名,如 a.github.io
和 b.github.io
,为了区分这两个域名,Mozilla 引入了有效顶级域名(Effective top-level domains)(eTLDs)的概念。
因此,站(Site)是有效顶级域名的下一级域名,即 eTLDs+1。
比如:a.web.dev
和 b.web.dev
属于同站,而 a.github.io
和 b.github.io
属于跨站。
由于 Cookie 与协议无关,HTTP 协议的页面也可以写入 Cookie。因此,为了提高安全性,在相同站(Site)的要求下,增加了协议(Scheme)检查。避免对 HTTP 站点的攻击影响到 HTTPS 站点。
Set-Cookie
中的 SameSite 值有 3 种。
Cookie 无法被第三方站点发出的请求携带,但可以在向第三方站点导航后,第三方站点的请求可以携带(如链接跳转)。为了避免 CSRF 攻击,Chrome 84 开始成为 SameSite 的默认值。
只能在第一方站点上发送的请求上携带。
在任何站点都可以被携带。如果 SameSite=None
,那么必须指定 Secure
属性,否则会无法写入。部分历史版本浏览器对 SameSite=None
不兼容,会表现为忽略 Cookie 或 Cookie 被当做 SameSite=Strict
被限制,参见 SameSite=None: Known Incompatible Clients。
与 SameSite=None
需要同时设置的 Secure 属性表示当前 Cookie 只能在 HTTPS 的请求中写入和携带。
SameSite 相关的策略主要分为两个阶段实施。
第一个阶段:SameSite 默认为 Lax,如果 SameSite 为 None,则必须设置 Secure。
第二个阶段:Schemeful SameSite
Chrome:88 版本开始灰度,参见:Schemeful Same-Site Design Doc
IETF 正在寻找一种替代 Cookie 的请求状态管理方案,来解决 Cookie 一些问题:
IEFT 希望 Cookie 可以有下面的一些特性:
为什么要采用一种新方案,而不是在现在的 Cookie 只上进行扩展?
短期方案:添加 SameSite=None; Secure; 升级到 HTTPS。 长期方案:尝试细分 Cookie 的使用场景,针对不同的 Cookie 设置不同的 SameSite 值。