Spring 单页应用程序:登录、注销等后 CSRF 令牌静默更改

San*_*jay 5 spring spring-mvc spring-security

据我所知,在 Spring+JavaScript 单页应用程序中,我们需要以某种方式将 CSRF 令牌发送到客户端。

推荐的方法是使用CsrfHeaderFilterSpring 指南中所述的方法。按照这种方法,当应用程序启动时,它会向服务器发送一个 GET 请求,从而获取令牌。

但是我看到在某些事件(例如loginlogout )下,Spring Security 会更改令牌。CsrfHeaderFilter提前出现,因此无法检测到更改。因此,我需要在此类事件之后发送另一个 GET 请求。

我尝试查看 Spring Security 代码以查找是否有办法将更改的令牌与这些登录注销请求一起发送,以便保存另一个 GET 请求。但是,找不到办法。

想知道是否像我现在所做的那样在登录注销等之后发送一个虚拟的 GET 请求看起来是一个很好的解决方案。或者,也许有更好的方法?

如果目前没有办法避免这个多余的 GET 请求,我想知道这是否会成为 Spring Security 提出一些可能之后的事情的票。

Ale*_*exK 2

遇到了关于 CookieCsrfTokenRepository 的类似情况。

我开发的应用程序有一个通过 REST 服务登录的自定义实现。该服务内部有 httpServletRequest.logout() 调用(据我所知)导致清除 XSRF-TOKEN cookie 作为响应:

Set-Cookie:XSRF-TOKEN=; Max-Age=0; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/ibdrs; Secure
Run Code Online (Sandbox Code Playgroud)

如果答案中没有新的 XSRF-TOKEN 值,我有两个选择:

  1. 登录后立即发出虚拟获取请求以获取新的 XSRF-TOKEN (如 OP 建议的那样)

  2. 在同一登录响应中获取更新的 XSRF-TOKEN,而不是清除 cookie。

事实证明,第二种选择可以通过以下方式实现:

  1. 制作了我自己的 CustomCookieCsrfTokenRepository 作为 CookieCsrfTokenRepository 的副本(源代码在这里)。如果它不是最终版本,那么扩展它而不是复制就足够了。

  2. 将副本中所有出现的 CookieCsrfTokenRepository 更改为 CustomCookieCsrfTokenRepository

  3. 将 saveToken 方法替换为从不清除 cookie 的新版本:

    @Override
    public void saveToken(CsrfToken token, HttpServletRequest request,
                      HttpServletResponse response) {
        if (token == null) {
            token = generateToken(request);
        }
        String tokenValue = token.getToken();
        Cookie cookie = new Cookie(this.cookieName, tokenValue);
        cookie.setSecure(request.isSecure());
        if (this.cookiePath != null && !this.cookiePath.isEmpty()) {
            cookie.setPath(this.cookiePath);
        } else {
            cookie.setPath(this.getRequestContext(request));
        }
        cookie.setMaxAge(-1);
        if (cookieHttpOnly && setHttpOnlyMethod != null) {
            ReflectionUtils.invokeMethod(setHttpOnlyMethod, cookie, Boolean.TRUE);
        }
        response.addCookie(cookie);
    }
    
    Run Code Online (Sandbox Code Playgroud)
  4. 配置 HttpSecurity 以使用新类:

    .csrf()
        .csrfTokenRepository(CustomCookieCsrfTokenRepository.withHttpOnlyFalse())
        .and()
    
    Run Code Online (Sandbox Code Playgroud)