新版chrome跨域问题:cookie之SameSite属性

最近在使用前后端分离开发的时候,遇到了一个诡异的问题,无论如何设置跨域,同一个页面获取到的session始终不一致。

事情的起始大概是这样的:

首先说一下我的业务逻辑,其实就是最常见的登录功能,获取验证码后存入session,用户提交登录时,将用户提交的验证码与从session里获取的验证码进行对比;功能简单,也好理解。可是却遇到了如下一系列问题:

发现问题:

  1. 登录界面前后端分离,ajax提交登录时出错。
  2. 验证码接口和登录接口的session不一致(跨域问题);
  3. 在网上搜索跨域问题,重新设置,问题依旧。

错因排除:

  1. ajax允许cookie(已经设置 xhrFields: { withCredentials: true} )。
  2. springboot尝试设置了多种跨域方法(springboot解决跨域)。

深入分析:

  1. 使用其它浏览器(firefox, ie),session却是一致的。。
  2. 对比chrome和firefox请求头和响应头:

firefox:首次发起请求后,服务端返回sessionId后,之后每次请求中的cookie都会带上sessionId。

chrome:请求头始终未携带sessionId,甚至整个cookie都为空,导致服务器每次都接受不到sessionId,每次都会重新分       配 一 个 session。


出现转机:
       搜索chrome未携带cookie原因,发现cookie新属性:SameSite(chrome77版本后支持) 。对该属性的介绍可以参考这篇文章:SameSite。同时,查看chrome的cookie,由于没有指明SameSite的取值,chrome默认将其设置为了Lax:

 

寻找解决方案:

  • DefaultCookieSerializer

   通过CookieSerializer ,我们可以手动的修改SameSite的值。

   @Bean
    public CookieSerializer httpSessionIdResolver() {
        DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer();
        cookieSerializer.setSameSite(null);
        return cookieSerializer;
    }

 注意,你的项目如果未做session分布式管理,可能需要引入以下依赖才能使用上述类。至于不同Chrome版本号的问题可以参考这篇文章:关于解决Chrome新版本中cookie跨域携带和samesite的问题处理

     
            org.springframework.session
            spring-session-core
            2.1.4.RELEASE
        

 

  • 设置CookieProcessor(待解决)

全局搜索SameSite,发现tomcat下的CookieProcessor提供了setSameSiteCookies方法,可是设置后无效,,可能是使用方法不对。

  • 设置response的header(推荐)

通过在后端中设置response.setHeader("Set-Cookie", "HttpOnly;Secure;SameSite=None"),响应头可以看到设置的Set-Cookie,但是chrome提示 如下:

由于设置SameSite为NONE时,需要同时设置secure,不设置secure无效,而设置secure之后,必须使用https来传输cookie。相对来说较为安全。
 

  • 我的最终方案:

继续查找资料的时候,幸运的找到了github上对于该问题的探究:New cross-site cookie not 'SameSite' warning in Chrome

看到其中的一条解决方案:  禁用chrome samesite。方法如下:

1. 在chrome中打开链接: chrome://flags/#site-isolation-trial-opt-out,搜索samesite

新版chrome跨域问题:cookie之SameSite属性_第1张图片

2.将上述三个选项禁用(设为disable)后重启chrome,问题解决。

新版chrome跨域问题:cookie之SameSite属性_第2张图片

 

总结:

      存在即合理,SameSite的设计初衷是为了防止CSRF攻击,禁用SameSite实际上并没有解决问题,属于下下策。这里提供一下我的理解,SameSite为了防止CSRF攻击,加强了对cookie的管理,防止用户带着cookie去访问第三方网站,而这又涉及到了跨域问题。然而,我们不可能要求用户像我们一样去禁用新版chrome的SameSite,目前的建议就是在header中设置samesite,即上述的response.setHeader("Set-Cookie", "HttpOnly;Secure;SameSite=None")后,使用https传输cookie。

时间问题文章逻辑可能并不严谨,仅供参考,如发现错误欢迎指正。

你可能感兴趣的:(spring,java,spring,boot,csrf,chrome,cookie)