Chrome浏览器升级到80版本后,对部分用户开启SameSite默认为Lax的特性,导致公司内部系统的一个功能出现问题,在此记录问题定位过程。
公司某个业务部门通过一个第三方网站,进行对外业务处理,同时需要将数据录入内部系统。该第三方网站支持通过iFrame形式将公司的内部系统,嵌入到该网站中。实际使用中,需要先登录我们的内部系统,然后在同一浏览器中访问该第三方网站。这一过程中依赖cookie跨域才能正常工作。
某一天某Mac用户在通过Chrome浏览器(版本80.0.3987.149)访问该第三方网站时,发现无法正常显示我们的内部系统。但通过Safari和FireFox浏览器依然能正常使用,便没有深入定位问题原因。 2天后,另一Windows用户发现通过Chrome(版本80.0.3987.149)也无法通过该第三方网站访问内部系统。但通过Firefox访问正常,且其他Chrome用户均可正常访问。在异常用户的Chrome中打开Dev Tools,查看Application->Cookies,发现在第三方网站下看不到内部系统的cookie。而正常访问用户下是可以在第三方网站下看到内部系统Cookie的,结合Console的提示信息
Warning提示: A cookie associated with a cross-site resource at http://{内部系统域名}.com/ was set without the ‘SameSite’ attribute. It has been blocked, as Chrome now only delivers cookies with cross-site requests if they are set with ‘SameSite=None’ and ‘Secure’. You can review cookies in developer tools under Application>Storage>Cookies and see more details at https://www.chromestatus.com/feature/5088147346030592 and https://www.chromestatus.com/feature/5633521622188032. Error提示: Mixed Content: The page at ‘https://{第三方网站域名}.cn//’ was loaded over HTTPS, but requested an insecure frame ‘http://{内部系统域名}.com//*’. This request has been blocked; the content must be served over HTTPS.
大致意思就是说内部系统的cookie没有指定SameSite属性,因此跨域请求被浏览器阻塞,现在Chrome仅仅发送设置了SameNote=None且是Secure的跨域请求。 同时控制台里给出了Chrome关于这个问题解释的文档连接,其中提到从76版本开始,Chrome就支持通过启用same-site-by-default-cookies flag来选择开启这个特性,从稳定的80版本开始默认开启这个特性。
再对比正常用户和非正常用户在第三方网站中访问内部系统的请求,发现异常用户的请求头中不包含cookie,因此对应的响应中重定向到http://{内部系统域名}.com/login页面了,从而导致了上面Console里面的Error日志。因此这个error日志是结果,warning日志才是根因。
到此,问题的根因就确定了,Chrome推行SameSite默认为Lax的策略,而我们内部系统没有设置SameSite从而导致Cookie无法在第三方网站中使用。那同样是最新版本Chrome,为什么有些用户不受影响?
在https://www.chromium.org/updates/same-site中,Chrome官方也给出了解释,他们也知道SameSite是“具有较大潜在破坏力的功能”,因此他们的策略是针对部分用户逐步推出,直到最终覆盖100%的Chrome用户。
关于SameSite的特性,参考阮一峰大神的博客
<CookieProcessor sameSiteCookies="None"/>
但是要求tomcat的版本的版本不低于8.5.42或9.0.21,参考链接:https://stackoverflow.com/questions/57505939/how-to-set-samesite-cookie-in-tomcats-cookie-processor 注意:大幅升级服务端的tomcat版本是有风险的,一定要进行充分的测试。
升级到Spring Session 2.1官方文档中,提到Spring Session 2.1版本支持设置SameSite,但这个版本依赖Spring 5.1,我们项目使用的是Spring4系列的版本。尝试把Spring Session Data Redis升级到2.1.0.RELEASE后,发现依赖的Spring全家捅都升级了,其中spring-data-commons 2.1.0版本相比较于spring-data-commons 1.13.23版本,CrudRepository接口的2个方法发生了修改。在我们项目中涉及到200多处的修改,且不包括其他方面影响性的测试。由于工作量太大,放弃了这个方法。因此这个方法是否实际可用,没有经过验证。在发现上述这些方法之前,在StackOverflow上搜索了与SameSite相关的内容,很多都不生效,可能跟Tomcat版本和Spring版本有关。 比如https://stackoverflow.com/questions/42998367/same-site-cookie-in-spring-security/60148509#60148509这里提到的这些方法,都尝试了,但不生效。 其中第二个回答中,在onAuthenticationSuccess里获取Set-Cookie响应头,并追加SameSite=None的方法,设置以后不生效,跟踪代码后,发现是tomcat中进行了判断,并拒绝更新我手动设置的header。各位可以尝试一下在你们的项目中是否生效。仅供参考。