相关文章推荐
豪气的哑铃  ·  SQL Connection - ...·  1 年前    · 
豪爽的炒面  ·  mysql ...·  1 年前    · 
憨厚的枇杷  ·  google和facebook ...·  1 年前    · 

cookie作为web浏览器的重要组成部分,经常被用于增加用户的体验,比如:记住登录名,购物车、跨域共享数据等,但同时也带来了如CSRF攻击的安全问题。自Chrome 80开始,谷歌对用户实施了新的cookie政策,该政策添加了对Samesite的IETF标准的支持,并且默认将cookie的samesite级别设置为lax,这种的策略阻止了开发者对第三方cookie操作,对很多涉及到跨域的系统造成了巨大的影响。

什么是cookie的samesite属性?

samesite是从chrome 51开始,cookie新增的属性,主要是用于防止csrf攻击和用户追踪的,主要的属性如下:(参考文档: Adobe Target和谷歌的SameSite Cookie政策 )

通过属性描述,可以了解到,samesite属性主要是用于控制跨站cookie的操作,默认情况下,属性为lax,在该属性下只有少数方式可以使用跨域cookie,这对很多现有的跨域系统带来巨大的困扰,需要通过将cookie的samesite设置为none才能让新的浏览器下的cookie像在旧浏览器下的cookie一样工作。同时,改配置必须与 Secure并行,也就是cookie必须通过https传输才能生效(该配置可以通过chrome配置去掉,服务端可以通过非https方式实现samesite=none的配置)。

如何解决(Java)

解决方案1:通过response写入(非HTTPS请求可以生效)

注意: setHeader与addHeader的区别

通过response设置header的时候,可以通过setHeader与addHeader两种方式进行设置,但是需要注意的是addHeader允许重复设置,而setHeader是不允许重复设置的,由于配置cookies的key为Set-Cookie,如果使用setHeader的方式进行设置,只会有一个cookie生效,所以在此需要用addHeader的方式进行设置。

setHeader源码

addHeader源码

解决方案2:基于springboot,修改tomcat配置 (参考Same-Site flag for session cookie in Spring Security)

经测试,该方案需要在springboot2.2.3版本以上,springboot内置版本为9.0.30才支持(更早版本未全部测试,2.1.*暂不支持)

该配置是通过重写定制化tomcat配置的方式,使所有的cookie都上samesite=None的配置。代码虽然在springboot2.1.6版本就可以用,但是并未生效。

网络方案(测试不一定通)

1、 通过filter重设cookie

网传解决方案

该方案在看起来没毛病,可是真实操作的时候,却有致命的问题,无论addSameSiteCookieAttribute方法中的for循环操作了几次,addHeader都不会改变header,cookie也不会写回客户端,这是因为,在tomcat下response在addHeader的时候,会判断response是否提交,若已经提交,addHeader将被直接跳过(Filter 中 addCookie 不生效问题)。

上图中addSameSiteCookieAttribute发生在doFilter之后,此时response的提交状态为已提交,所以将不会再往header里面添加内容,故功能无法实现。若将addSameSiteCookieAttribute提前,由于filter比controller早执行,无法拿到controller层的cookie,亦无法达到效果。

response的isCommitted是什么时候提交的?

springMvc的RequestMappingHandlerAdapter进行请求处理后 ,会进行一次prepareResponse的操作,该操作会将response设置为已提交。

2、 使用AOP方式重设cookie

此段代码亲测可行,可是存在一个不可靠的因素,因为addHeader是往header中添加cookie,不会删除原有的cookie,这就会导致返回报文中,有对同一个cookie设置的情况。该情况在不同浏览器下体现不一样。对于这种模棱两可的因素,不用为妙。

chrome80下的情况,如下:

chrome80下

360浏览器的情况如下:

360情况下