Chrome 51 开始,浏览器的 Cookie 新增加了一个SameSite属性,主要用于防止CSRF攻击和用户追踪。

为什么这时候来讲这个事情呢,在Chrome 80之后,由于SameSite默认值的改变,导致大部分浏览器在跳转跨站的网站时没有携带Cookie,造成登录态失效等一系列问题。

为了保护保护用户隐私,Safari更加直接,默认直接禁用了第三方携带Cookie。导致链接跳转或者接口请求第三方都无法携带Cookie。最直观的就是,比如,当前网页有一个 GitHub 链接,用户点击跳转就不会带有 GitHub 的 Cookie,跳转过去总是未登陆状态。

在分析SameSite之前,我们有必要先来了解一下跨站和跨域的区别。

说到浏览器的跨站和跨域,个人觉得很多人容易混淆。虽然一字之差,但是不管是概念还是作用上,都有蛮大的区别的。接下来我们来一起学习以下。

跨域

跨域对应的是同域,同域即是浏览器的同源策略,这里不单单是指相同域名,域名、协议、端口号必须完全一致,才属于同源。只要其中一个不相同,都是属于跨域了。

跨域的解决方案有很多,可以在其他渠道学习下,比较常用的是JSONPCORSnew Image等。

跨域主要是针对请求的。如果跨域,浏览器会在控制台提示类似的Error

上面导致跨域的原因是端口号不一致。

跨站

跨站对应的是同站,也可以称呼叫做第一方(同站)或者第三方(跨站)。同源策略作为浏览器的安全基石,其「同源」判断是比较严格的。相对而言,Cookie中的「跨站」就相对宽松一些,只要协议相同,并且有效顶级域名+二级域名相同即可,不用考虑端口号。文字比较晦涩,讲个例子就简单很多了。

同站:zhuanlan.zhihu.comzhihu.com.com属于顶级域名,而.zhihu属于二级域名。这里属于同站,但是跨域了。

跨站: zhihu.combaidu.coma.github.iob.github.io。第一个例子虽然顶级域名相同,但是二级域名不一样了。第二个例子看起来会觉得奇怪,这里github.io属于顶级域名,ab才是二级域名,所以这里也跨站了。

再比如,http://a.zhihu.comhttps://zhuanlan.zhihu.com,虽然顶级域名和二级域名相同zhihu.com,但是因为他们的协议不同,也属于跨站。

看完例子后,可以给个简单的结论:跨站一定跨域,跨域不一定跨站

SameSite

简单的讲完跨域和跨站之后,我们来看下这边文章的主题部分。

开头就有提到,SameSite属性可以让 Cookie 在跨站请求时不会被发送,从而阻止了跨站请求伪造攻击(CSRF)。它有三个属性值

  1. Strict 完全禁止第三方 Cookie,跨站点时,任何情况下都不会发送 Cookie。
  2. Lax 允许部分第三方请求携带 Cookie。
  3. None 无论是否跨站都会发送 Cookie。

Chrome的SameSite默认值是Lax,而Safari的默认值是Strict。

可以看下github关于SameSite的处理。

大部分的Cookie都是浏览器的默认值Lax,当然还有 Strict这种严格禁用第三方Cookie发送的,还有个None,即无论是否跨站都会发送该Cookie

以前呢,SameSite的默认值是None, 即当前页面嵌入其他第三方页面(iframe)、POST请求、Ajax都可以携带第三方的Cookie。但是默认值调整了之后,会产生一些影响,我们先来看看默认值改变之后,Cookie的发送情况

从上图可以看出,对大部分 web 应用而言,POST 表单,iframe,AJAX,Image 这四种情况从以前的跨站会发送三方 Cookie,变成了不发送。

POST表单和AJAX请求在跨站请求的时候不发送Cookie是ok的, 这样可以有效阻止跨站请求伪造攻击。

Image不发送Cookie其实影响比较小,因为大部分静态资源都会放在CDN上, 不随业务变化,可以实现强缓存。

而iframe一般都是跨站的,所以受影响相对较大。

解决

方法一:

可以将SameSite设置为None,但是这里需要注意。

  • SameSite=none 只支持HTTPS接口。如果要设置该值,需要在对应的Cookie上同时设置Secure属性。
  • 部分浏览器不支持部分SameSite=none。IOS 12 的 Safari 以及老版本的一些 Chrome 会把 SameSite=none 识别成 SameSite=Strict,所以服务端必须在下发 Set-Cookie 响应头时进行 User-Agent 检测,对这些浏览器不下发 SameSite=none 属性

方法二:

既然浏览器针对SameSite的默认值实现不一致,在跨站的时候会部分或者完全禁用携带第三方Cookie,那我们在跨站请求接口或者链接跳转的时候,比如 jd.comjinrong.com,这样处理呢(滑稽)

  • jd.com页面发生请求或者跳转时,生成唯一标识的值。将Cookie和唯一标识存储到服务器。
  • 在进入到jinrong.com页面或者相关接口时,提前根据唯一标示,获取到对应的Cookieset到浏览器,再处理业务逻辑。
  • 最后就可以实现跨站携带Cookie了。

大概就是将跨站前将Cookie存到数据库,跨站后将Cookieset到浏览器,再做其他一系列业务逻辑。

总结

  • 跨站一定跨域,跨域不一定跨站
  • 只要有效顶级域名+二级域名不相同,就属于跨站
  • SameSite的作用是防止跨站请求伪造(CSRF)攻击和保护用户隐私
  • Chrome的SameSite默认值是Lax,而Safari的SameSite默认值是Strict

参考资料

Cookie 的 SameSite 属性 www.ruanyifeng.com图标 Safari浏览器默认将完全阻止第三方Cookie www.ruancan.com图标 浏览器系列之 Cookie 和 SameSite 属性 github.com