前置解释
- 同源策略限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互,要求协议,端口和主机都相同。
- HTTP 是一个无状态的协议,所谓无状态协议,简单的理解就是即使同一个客户端连续两次发送请求给服务器,服务器也识别不出这是同一个客户端发送的请求
- Cookie 是客户端保存用户信息的一种机制,保存在客户机硬盘上。可以由服务器响应报文 Set-Cookie 的首部字段信息或者客户端 document.cookie 来设置,并随着每次请求发送到服务器。子域名可以获取父级域名 Cookie。
SameSite 来源
熟悉 web 安全攻击 CSRF 的都知道 CSRF 的本质实际上是利用了 Cookie 会自动在请求中携带的特性,诱使用户在第三方站点发起请求的行为。针对这个问题浏览器厂商对此给 cookie 加了 SameSite 属性。 Chrome 于 2015 年 6 月支持了该属性,Firefox 和 Safari 紧随其后也增加了支持。
同域和同站
- 同域是指两个 URL 的协议/主机名/端口一致,判断比较严格。
- 同站判断就比较宽松,根据 Mozilla 维护的公共后缀表(Pulic Suffix List[2])使用有效顶级域名(eTLD)+1 的规则查找得到的一级域名是否相同来判断是否是同站请求。
例如:
.org 是在 PSL 中记录的有效顶级域名,imnerd.org 则是一级域名。所以 https://blog.imnerd.org 和 https://www.imnerd.org 是同站域名。
.github.io 也是在 PSL 中记录的有效顶级域名,所以 https://lizheming.github.io 和 https://blog.github.io 得到的一级域名是不一样的,他们两个是跨域请求。
SameSite 值
SameSite 属性有以下几个值:
- SameSite=None:无论是否跨站都会发送 Cookie
- SameSite=Lax:允许部分第三方请求携带 Cookie
- SameSite=Strict:只发送相同站点请求的 Cookie,即当前网页 URL 与请求目标 URL 完全一致。
Strict
Strict 最为严格只发送相同站点请求的 Cookie,即当前网页 URL 与请求目标 URL 完全一致。浏览器做了仅针对 HTTPS 域名才支持 SameSite=None 配置。所以如果你要设置 SameSite=None 的话,则必须还要携带 Secure 属性才行。
例如对于一个普通的站点,如果一个已经登录的用户跟踪一个在电子邮件上的网站链接,这个站点将不会收到 Cookie ,用户访问该站点还需要重新登陆。
Lax
对于允许用户从外部链接到达本站并使用已有会话的网站站,默认的 Lax 值在安全性和可用性之间提供了合理的平衡。 Lax 属性只会在使用危险 HTTP 方法发送跨域 Cookie 的时候进行阻止,例如 POST 方式。同时,使用 JavaScript 脚本发起的请求也无法携带 Cookie。
lax
从上图可以看出,对大部分 web 应用而言,Post 表单,iframe,AJAX,Image 这四种情况从以前的跨站会发送三方 Cookie,变成了不发送。
none
浏览器会在同站请求、跨站请求下继续发送 Cookies,不区分大小写。
策略改变带来的影响
在 Chrome 80+ 版本中,SameSite 的默认属性是 SameSite=Lax。如果想要指定 Cookies 在同站、跨站请求都被发送,那么需要明确指定 SameSite 为 None。Chrome 也宣布,将在下个版本也就是 Chrome 83 版本,在访客模式下禁用三方 Cookie,在 2023 年全面禁用三方 Cookie。
- 使用的三方埋点数据异常
- 依赖 cookie 智能广告推荐失败
- 跨站请求 cookie 丢失、统一登录、支付等失败
FLoC
FLoC 通过获取浏览器的浏览记录将用户加入 “相似” 用户的分组内,每个分组拥有对应的 FLoC ID。有别于之前使用 Cookie ID 标记直接将用户行为数据传递到广告商网站处理的方式。它提出了 document.interestCohort() 这个新的 API,将用户的行为在本地转换成了不带个人隐私的关键词,既规避了用户隐私问题,同时又解决了广告的精准投放问题。
谷歌在 Chrome 浏览器的 89 版本上小规模测试了代替 cookie 的 FLoC(Federated Learning of Cohorts, 联邦学习群组)技术。
微软、Opera、Firefox、GitHub,EFF 等都对此表达了反对意见。
如果不想启用你可以:
- 给站点添加相关的拒绝标头:Permissions-Policy: interest-cohort=() 可以屏蔽
- 使用表示拒绝的浏览器:Brave、Vivaldi
- 使用表示暂时不会跟进的浏览器:Mozilla Firefox、Microsoft Edge
Cookie 作用域处理
- 同域名
当访问同域名下的页面时,Cookie 会正常携带,后台服务即可直接获取到对应的 SessionID 值,后台为单服务还是多服务无差别。 - 不同子域名
子域名间 Cookie 是不共享的,但各子域名均可获取到父级域名的 Cookie,即 m.dewu.com 与 jiawu.dewu.com 均可以获取 dewu.com 域名下的 Cookie。所以可以通过将 Cookie 设置在父级域名上,可以达到子域名共享的效果。 - 完全不同域名
不同域名是无法直接共享 Cookie ,可以选择将 Session ID (或 Token )保存到浏览器的 LocalStorage 中,也可以通过特殊手段将它写入多个其他域下的 LocalStorage 中,让前端在每次向后端发送请求时,主动将 LocalStorage 的数据传递给服务端。
1 | // 获取 token |
前端通过 iframe+postMessage() 方式,将同一份 Token 写入到了多个域下的 LocalStorage 中,前端每次在向后端发送请求之前,都会主动从 LocalStorage 中读取 Token 并在请求中携带,这样就实现了同一份 Token 被多个域所共享。
也可以 CAS(Central Authentication Service)中央认证服务,是 Yale 大学发起的一个开源项目,旨在为 Web 应用系统提供一种可靠的单点登录方法。