阅读 243

【Cookie 的 SameSite 属性】当Chrome版本升级后三方Cookie被禁用

笔者正在漫漫前端路上,文中如有不正确、不恰当的地方请评论告诉我,非常感谢! 😊 

前言

年初,我们小组在对接操作员中心时遇到了这样一个问题:登录成功后Cookie无法传递导致登录状态失效。经过排查发现,当服务端通过 Set-Cookie 响应头设置 Cookie 到客户端时,Chrome浏览器发出警告:Cookie的SameSite默认为Lax,因此部分跨站请求将不携带此Cookie。

bug图.png

原来Google在2020年2月4号发布的 Chrome 80 版本,将没有声明SameSite值的cookie默认设置为SameSite=Lax,以此来减少非安全第三方 cookie 的使用。

初学者的我有了疑问:SameSite属性是什么?Chrome为什么要这样做?我们要如何应对这一改变?带着这些疑问跟着本文来深入理解SameSite。

CSRF攻击

要了解SameSite属性,那就不得不提到CSRF攻击。

CSRF,全称Cross-site request forgery,意为跨站请求伪造。是指一些恶意网站会诱导用户向被攻击网站发送跨站请求,利用用户已获得的登录状态绕过后台的用户验证,达到冒充用户对被攻击的网站执行某项操作的目的。

比如GET类型的CSRF攻击非常简单,只需要一个HTTP请求:

 <img src="http://bank.example/withdraw?amount=10000&for=hacker" > 
复制代码

之前用户登录了信任的网站A,并且保存登录状态。在他访问含有这个img的恶意页面后,浏览器会自动发出一次HTTP请求,bank.example就会收到包含用户登录信息的一次跨域请求,往黑客账户中转账1W元。

Cookie 往往用来存储用户的身份信息,作为浏览器和服务器之间维护登录状态的一个关键数据。而恶意网站正是利用了Cookie达到CSRF攻击。

与当前站点的域相匹配的 Cookie,即浏览器地址栏中显示的内容,被称为第一方Cookie。同样,来自当前站点以外的域的 cookie 被称为第三方cookie。第三方 Cookie除了被用于 CSRF 攻击,还被用于用户追踪,成了各大广告和购物网站窥探用户隐私的利器。

cookie图.png

因此,为了阻止不明外域的访问、防止CSRF攻击和用户追踪,从Chrome 51 开始,浏览器的 Cookie 新增加了一个SameSite属性。

SameSite属性

Cookie 的SameSite属性的引入,将允许用户指定是否将cookie限制为相同站点的请求。它可以设置三个值:

  • Strict 最为严格,完全禁止第三方 Cookie,只有当前网页 URL 与请求目标 URL 完全一致才会带上Cookie。
  • Lax 允许部分第三方请求携带 Cookie,具体见下图。
  • None 无论是否跨站都会发送 Cookie

samesite属性值.png

这里需要理解 [同源/跨域] 和 [同站/跨站] 的区别。

浏览器同源策略(SOP)中的「同源(same-origin)]是指两个 URL 的协议/主机名/端口一致。例如,www.baidu.com/pages/...,它的协议是 https,主机名是www.baidu.com ,端口是 443。

同源策略作为浏览器的安全基石,其「同源」判断是比较严格的,相对而言,Cookie中的「同站」判断就比较宽松:只要两个 URL 的 eTLD+1 相同即可,不需要考虑协议和端口。其中,eTLD 表示有效顶级域名,例如,.com、.co.uk、.github.io 等。eTLD+1 则表示,有效顶级域名+二级域名,例如 taobao.com 等。

举几个例子,www.baidu.comwww.juejin.com 是跨站,www.a.juejin.com 和 www.b.juejin.com 是同站,www.a.juejin.com:80www.a.juejin.com:3000 是跨域。

对于防范 CSRF 攻击,我们可以针对实际情况将一些关键的 Cookie 设置为 Strict 或者 Lax 模式,这样在跨站点请求时,这些关键的 Cookie 就不会被发送到服务器,从而使得黑客的 CSRF 攻击失效。

虽然该SameSite属性得到了广泛的支持,但遗憾的是它并未被开发人员广泛采用,依旧使用户容易受到 CSRF 和无意信息泄露的影响。因此Chrome采取了开头所说的SameSite默认策略,将没有声明SameSite值的cookie默认设置为SameSite=Lax。而这会让一些使用第三方cookie场景的系统,造成登陆异常、系统崩溃等大问题。

解决方案

SameSite默认策略造成的影响不可疏忽。有人提出修改客户端浏览器设置,禁用“SameSite by default cookies”,简单粗暴,但这只是个应急方案,这违背了BS架构应用的最大优点,开发者无法为所有客户端安装部署。那么开发者该如何应对呢?以下浅陋地提出了几种应对方案。

Ngnix反向代理解决跨域问题

既然不支持三方cookie,那我们就解决跨域问题。本文不细说啦。

设置 SameSite 为 none

由服务端将response的header设置Set-Cookie:SameSite=None,允许跨站请求发送 Cookie。

不过有两点需要特别注意:

  1. HTTP 接口不支持 SameSite=none

如果你想加 SameSite=none 属性,那么该 Cookie 就必须同时加上 Secure 属性,表示只有在 HTTPS 协议下该 Cookie 才会被发送。这也意味着,你的网站需要向https迁移,这也让你的网站更安全。

Set-cookie: key=value; SameSite=None; Secure
Set-cookie: key=value; Secure
复制代码
  1. 需要 UA 检测,部分浏览器不能加 SameSite=none

IOS 12 的 Safari 以及老版本的一些 Chrome 会错把 SameSite=none 识别成 SameSite=Strict,所以服务端必须在下发 Set-Cookie 响应头时进行 User-Agent 检测来判断是否加上SameSite=none。

Electron的useSessionCookies

但服务端修改响应头的方法并不适用于我们当前场景,因为我们无法修改操作员中心接口。我们的产品FIP基于Electron,Electron基于 Node.js 和 Chromium,于是我们将目光转向Electron,看看它是否有解决方案。

反复翻阅Electron官方文档后发现,Electron使用Chromium的原生网络库发出HTTP / HTTPS请求,其请求对象有以下两个神秘的参数:

  • session Object (可选) - 与请求相关联的Session实例.
  • useSessionCookies Boolean (可选) - 是否从提供的会话与请求一起发送cookie。

这个session实例负责管理浏览器会话、cookie等,当服务端返回 Set-Cookie响应头时,Electron会将该 Cookie 存储在与请求相关联的Session实例中;当useSessionCookies为true 时,在下次向服务器发送请求时,会携带上之前存储的Session实例中的 Cookie。虽然这绕开了SameSite默认策略,但或许会带来一些安全问题。

小结

本文介绍了sameSite属性的产生背景和作用,介绍了Chrome80+ SameSite默认策略带来的影响,最后浅陋地提出了几种应对方案。

虽然Chrome这一改变,让开发者加了波班,但这也说明了Chrome对前端安全和用户隐私的重视,鼓励开发者主动为用户提供更安全的体验,而不是依赖于浏览器的默认行为。

参考

预测最近面试会考 Cookie 的 SameSite 属性

阮一峰-Cookie 的 SameSite 属性

文章分类
前端
文章标签