深入研究HTTP跨站请求

背景

Chrome浏览器升级到80以后,对属性SameSite的默认值从None改为了Lax,从而导致我们的个别线上应用突然间拉胯了。

为什么该改动会影响线上系统呢,在此得先描述一下受影响应用的特点:

三方系统引入,我们当时采用的Iframe方案,也就是在系统A(a.xx.cn)中的页面通过Iframe加载系统B(b.com.cn)

异常原因

经过分析后发现,内嵌的系统B无法读取自己设置的Cookie,导致一系列的问题。

是不是很奇怪,系统B自己设置的Cookie,自己读不了。

Why?

在分析前,首先我们得先了解一下,属性SameSite的含义:

image

简单来说,SameSite是响应头的一个属性,它的值会决定跨站访问的时候是否允许发送Cookie。SameSite的值有三个:Strict,Lax,None。

  • Strict:

    最为严格,跨站访问的时候,完全不允许发送Cookie

  • Lax:

    规则稍微放松,跨站访问的时候,链接,预加载请求,GET表单可以发送Cookie

  • None:

    不限制,跨站访问的时候都可以发送Cookie

请注意,我们在描述的时候,一直都加前缀“跨站访问的时候”,那什么是跨站?很多人会和跨域混淆,它俩在定义上是不同的。

  • 跨域:

    非简单请求,如果和请求目标在协议,域名,端口有一个不一样,就认为是跨域。

  • 跨站:

    如果两个站点,公共后缀(public suffix list)里的域名相同,并且再上一级也相同,就认为是同站。反之就是跨站。

公共后缀(public suffix list)

是一份顶级域名列表,最早是由Mozilla提出,目前已经被主流浏览器采用。

举个例子方便大家了解,下面两个站点:a.teld.cn,b.teld.cn

  • 是跨域么?很明显,是跨域,因为域名不同。

  • 是跨站么?我们根据规则来看,公共后缀列表里,注册的顶级域名是cn,cn前面一级是teld,都相同,所以不是跨站。公共后缀有一份列表,大家可以自行搜索查看。

好,目前为止,我们已经弄清楚跨域和跨站的区别。而属性SameSite只是影响跨站访问的情况。我们再回过头看第一句话“Chrome浏览器升级到80以后,对属性SameSite的默认值从None改为了Lax

那80版本以前是什么样呢?

80以前,SameSite的默认值是None,也就是说我们在跨站访问的时候,都可以发送Cookie。下面举个例子(聚焦前后端分离的场景,服务端写Cookie,暂时忽略):

document.cookie = "test=1; Max-Age=2600000; "

80以前跨站的时候,写读很正常。但80以后呢,SameSite的默认值改为了Lax,那跨站的时候,自然就读不到了。

怎么解?第一想法就是把默认值设置成None(80以上版本要求设置None的时候,必须设置Secure)

document.cookie = "test=1; Max-Age=2600000; SameSite=None; Secure"

80以上版本是解决了,哪80版本以下呢?这就不得不说一下兼容性问题,下面是谷歌的升级说明(点击放大查看):

image

简单来说就是:早期的版本并不能正确识别None,而且各个系统浏览器的行为还不一致,有的会将SameSite=None的Cookie直接拒绝,而有的就会解释为SameSite=Strict,和我们的期望大相径庭。

怎么解?目前通用的方案是多设置一个Cookie,如果Cookie读写方法封装起来的话,该操作对业务也是无感的,示例如下:

document.cookie = "test=1; Max-Age=2600000; SameSite=None; Secure"

多设置一个,当读取的时候,先读test,如果发现没有再读__test。

还有一种方案是通过UA检测,进行浏览器黑名单的确认然后针对性处理。虽然双Cookie在资源上有浪费,但考虑到国内纷繁复杂的浏览器环境,个人更推荐双Cookie的解决方案。

到这里问题结束了么?

  • 如果系统是Windows,问题结束了

  • 如果系统是Android,问题结束了

  • 如果系统是IOS或iPadOS,并且使用的Safari,那么尴尬依旧存在

因为从iOS 和 iPadOS 13.4 开始,Safari增加了智能反追踪功能,如图:

image

并且“阻止跨网站跟踪”默认是开启的,意思就是拒绝所有的跨站请求传送Cookie,可以理解为设置SameSite=Strict,所以如果是ToC系统,要考虑苹果Safari用户的话,上述处理都有瑕疵。

总结

所以,跨站问题要处理到什么程度,要结合自身系统特点来判断。比如:

  • 网站并不依赖Cookie,那么恭喜你,跨站对你没任何影响。

  • 少量依赖,看看是否可以考虑PostMessage的方式

  • 内部系统的话是否可以限制浏览器版本

  • 通过Nginx层面的域名处理,把跨站变为非跨站

技术没有银弹,只要我们深入了解跨站请求的机制和原理,在合适的场景采用合适的技术策略,跨站问题最终将迎刃而解。

你可能感兴趣的:(深入研究HTTP跨站请求)