SameSite 那些事

《Web 安全漏洞之 CSRF》中咱们了解到,CSRF 的本质其实是利用了 Cookie 会自动在请求中携带的特性,诱使用户在第三方站点发起请求的行为。除了文中说的一些解决方式以外,标准还专门为 Cookie 增长了 SameSite 属性,用来规避该问题。Chrome 于 2015 年 6 月支持了该属性,Firefox 和 Safari 紧随其后也增长了支持。SameSite 属性有如下几个值:html

  • SameSite=None:不管是否跨站都会发送 Cookie
  • SameSite=Lax:容许部分第三方请求携带 Cookie
  • SameSite=Strict:仅容许同站请求携带 Cookie,即当前网页 URL 与请求目标 URL 彻底一致

该属性适合全部在网页下的请求,包括但不限于网页中的 JS 脚本、图片、iframe、接口等页面内的请求。能够看到 None 是最宽松的,和以前的行为无异。而 LaxStrict 都针对跨站的状况下作了限制。其中 Strict 最为严格,不容许任何跨站状况下携带该 Cookie。Lax 则相对宽松一点,容许了一些显式跳转后的 GET 行为携带。如下是一个带有 SameSite 属性的标准 Cookie 响应示例:前端

Set-Cookie: name=lizheming; SameSite=None; Secure

须要注意的是,浏览器作了仅针对 HTTPS 域名才支持 SameSite=None 配置。因此若是你要设置 SameSite=None 的话,则必须还要携带 Secure 属性才行。git

Same Site

Same Site 直译过来就是同站,它和咱们以前说的同域 Same Origin 是不一样的。二者的区别主要在于判断的标准是不同的。一个 URL 主要有如下几个部分组成:github

能够看到同域的判断比较严格,须要 protocol, hostname, port 三部分彻底一致。相对而言,Cookie 中的同站判断就比较宽松,主要是根据 Mozilla 维护的公共后缀表(Pulic Suffix List)使用有效顶级域名(eTLD)+1的规则查找获得的一级域名是否相同来判断是不是同站请求。web

例如 .org 是在 PSL 中记录的有效顶级域名,imnerd.org 则是一级域名。因此 https://blog.imnerd.orghttps://www.imnerd.org 是同站域名。而 .github.io 也是在 PSL 中记录的有效顶级域名,因此 https://lizheming.github.iohttps://blog.github.io 获得的一级域名是不同的,他们两个是跨域请求。chrome

在相似 GitHub/GitLab Pages, Netlify, Vercel 这种提供子域名给用户建站的第三方服务中,eTLD 的这种同站判断特性每每很是有用。经过将本来是一级域的域名添加到 eTLD 列表中,从而让浏览器认为配有用户名的完整域名才是一级域,有效解决了不一样用户站点的 Cookie 共享的问题。跨域

eTLD

eTLD 的全称是 effective Top-Level Domain,它与咱们往常理解的 Top-Level Domain 顶级域名有所区别。eTLD 记录在以前提到的 PSL 文件中。而 TLD 也有一个记录的列表,那就是 Root Zone Database。RZD 中记录了全部的根域列表,其中不乏一些奇奇怪怪五花八门的后缀。浏览器

eTLD 的出现主要是为了解决 .com.cn, .com.hk, .co.jp 这种看起来像是一级域名的但其实须要做为顶级域名存在的场景。这里还能够分享一个有趣的事情,2020年5月份出现了一块儿阿里云全部 ac.cn 后缀网站解析所有挂掉的事件。缘由就是 ac.cn 是中科院申请在册的 eTLD 域名。而阿里云的检测域名备案的脚本不了解规范,没有使用 PSL 列表去查找一级域名,而是使用了.分割的形式去查找的。最终全部 *.ac.cn 的域名因为 ac.cn 这个域名没有进行备案致使解析所有挂掉。而咱们如今知道 ac.cn 这个域名是 eTLD 域名,它确定是没法备案的。安全

Schemeful Same Site

在 Chrome 86/Firefox 79 中,浏览器增长了一个 Schemeful Same Site 的选项,将协议也增长到了 Same Site 的判断规则中。可是并非彻底的不等判断,能够理解是否有 SSL 的区别。例如 http://https:// 跨站,但 wss://https:// 则是同站,ws://http:/ 也算是同站。cookie

Chrome 能够浏览器输入 chrome://flags/#schemeful-same-site 找到配置并开启。

Lax

咱们知道互联网广告经过在固定域 Cookie 下标记用户 ID,记录用户的行为从何达到精准推荐的目的。随着全球隐私问题的整治,同时也是为了更好的规避 CSRF 问题,在 Chrome 80 中浏览器将默认的 SameSite 规则从 SameSite=None 修改成 SameSite=Lax。设置成 SameSite=Lax 以后页面内全部跨站状况下的资源请求都不会携带 Cookie。因为不会为跨站请求携带 Cookie,因此 CSRF 的跨站攻击也无从谈起,广告商也没法固定用户的 ID 来记录行为。

对用户来讲这确定是一件好事。可是对咱们技术同窗来讲,这无疑是上游给咱们设置的一个障碍。由于业务也确实会存在着多个域名的状况,而且须要在这些域名中进行 Cookie 传递。例如多站点使用 SSO 登陆、接入统一的验证码服务、前端和服务端接口属于两个域名等等状况,都会由于这个修改受到影响。

这个修改影响面普遍,须要网站维护者花大量的时间去修改适配。而 Chrome 80 于 2020 年 2 月发布后全球就开始面临新冠疫情的影响。考虑到疫情问题后续的版本里又暂时先回退了这个特性(相关连接),最终是在 Chrome 86 进行了全量操做。

针对由于这次特性受到影响的网站,能够选择如下一些适配办法:

  1. 使用 JWT 等其它非 Cookie 的通讯方式
  2. 为 Cookie 增长 SameSite=None;Secure 属性配置
  3. 全部的跨域接口增长 Nginx 代理,使其和页面保持同域

每一种方法都须要一些取舍。第一种更换 Cookie 的方式改形成本很是高,特别是在有外部业务对接的状况下基本不可能。第三种方式经过将跨域变为同域的转发方式可能会带来线上流量的成倍增长,也是须要考虑的因素。第二种设置成 None 看起来是比较简单的办法,不过也有着诸多的限制。

  1. SameSite=None;Secure 因为仅支持 HTTPS 页面,因此若是有 HTTP 的场景须要考虑跳转至 HTTPS 或者选择其余方案;
  2. 因为 SameSite 属性是后来才加入的,一些老浏览器(其实就是 IE)会忽略带有这些属性的 Cookie,因此须要同时下发未配置 SameSite 属性和配置 SameSite 属性的两条 Set-Cookie 响应头,这样支持和不支持的会各取所需;
  3. 在 Safari 的某些版本中会将 SamteSite=None 等同于 SameSite=Strict 因此部分 Safari 场景须要特殊处理不进行下发(相关连接);

综上使用代理转发的方式是我比较推荐的方式,除了不那么绿色以外兼容问题处理仍是不错的。

SameParty

SameSite=None 断了咱们跨站传递 Cookie 的念想,但实际业务上确实有这种场景。例如 Google 本身就有很是多的域名,这些域名若是都须要共享登陆 Cookie 的话可能就会很是困难了。针对这种某个实体拥有多个域名须要共享 Cookie 的状况,就有人(那其实就是 Google 的同窗)提出了 [SameParty](
https://github.com/cfredric/s... 的概念。

该提案提出了 SameParty 新的 Cookie 属性,当标记了这个属性的 Cookie 能够在同一个主域下进行共享。那如何定义不一样的域名属于同一主域呢?主要是依赖了另一个特性 first-party-set 第一方集合。它规定在每一个域名下的该 URL /.well-known/first-party-set 能够返回一个第一方域名的配置文件。在这个文件中你能够定义当前域名从属于哪一个第一方域名,该第一方域名下有哪些成员域名等配置。

固然使用固定 URL 会产生额外的请求,对页面的响应形成影响。也能够直接使用 Sec-First-Party-Set 响应头直接指定归属的第一方域名。

不过 W3C TAG 小组已经强烈拒绝了该提案(来源)。W3C 认为该提案从新定义了网站沙箱的边界,带来的影响可能不只仅只是 Cookie 共享这么简单,包括麦克风、摄像头、地理信息等隐私设置都须要去从新评估影响。

同时该提案可能会和用户的预期不一致,若是 Google 和 Youtube 被定义成第一方网站进行共享的话,那 Google 就能很轻松的获取到用户在 Youtube 上的行为,可能用户并不想要这样。

W3C TAG 小组全称是 Technical Architecture Group,即 W3C 技术架构组。TAG 是 W3C 专一于 Web 架构管理的特殊小组。其使命是为 Web 架构的设计原则寻求共识,且在必要时梳理并澄清这些设计原则,帮助协调 W3C 内部及外部跨越不一样技术的架构定义与研发工做。基本能够认为它是 Web 基础规范定义的小组。另外万维网之父 Tim Berners-Lee 也在 TAG 小组中。

不过 W3C 说的有理没理,都阻挡不了 Chrome 去实现这个功能。在 Chrome 89 中已经增长了 SameParty 的相关逻辑,只是目前没有默认开启。目前在 DevTools 中是能够看到 Cookie 的 SameParty 属性列的。Edge 因为使用了 Chromium 也在同版本支持了该功能。只掌管了规范,没有掌管实现,当某一方浏览器实现了“霸权”的状况下,W3C 的处境就变得尴尬了起来。

FLoC

SameSite 除了影响单实体多域名共享 Cookie 的状况,最大的问题其实就是互联网广告获取用户行为了。因为广告挂载页面和广告不在同域,因此广告没法得到用于标记用户 ID 从而对用户行为进行聚类。为了解决这个问题,有人(其实也是 Google 的同窗)提出了 Federated Learning of Cohorts 同盟学习队列提案。

有别于以前使用 Cookie ID 标记直接将用户行为数据传递到广告商网站处理的方式。它提出了 document.interestCohort() 这个新的 API,将用户的行为在本地转换成了不带我的隐私的关键词,既规避了用户隐私问题,同时又解决了广告的精准投放问题。

不过这看似美好的东西却遭到了各大网站和浏览器的强力抵制,bravVivaldiduckduckgoGitHub 以及 Edge,Firefox,Safari(来源)都纷纷发表了拒绝支持的观点和行动。

社区主要的担忧点在于,新的特性的增长可能会增长特征值为隐私嗅探提供了更广阔的入口。并且经过该 API 能获取到以前碍于权限没法程序获取的用户浏览数据。目前 Chrome 已经支持了这个功能,不过须要开启 Flag 才能支持。amIFLoCed 是一个用来检测你的浏览器是否开启了 FLoC 追踪特性的网站,可使用它检测你的浏览器是否应用该特性。

后记

为了解决 CSRF 问题,Chrome 强推了 SameSite=Lax 做为默认配置。随之而来的,不只是全球开发者的配合修改,还形成了已有场景的没法知足。而为了知足现有场景,又提出了 SamePartyFLoC 两个方案。这种行为不知可否成为浏览器的内卷行为?

SameSite 属性自己是没有什么问题的,但我的认为它应该是一种 CSRF 问题的选择方案,浏览器将其默认修改为 SameSite=Lax 就有点难受了。大部分企业项目里都已经采用其余 CSRF 防范方式规避了该问题,而 Lax 配置又存在着兼容性问题,不能让咱们彻底免顾 CSRF 之忧。

随着全球隐私问题的白热化,不知道还有什么新的提案搞出来须要咱们全球开发者为其买单。

参考资料: