0

我在 XSRF 令牌生成和更新必要的 cookie 值方面遇到了一些奇怪的行为。当我加载我网站的登录页面时——一个 Angular 前端和一个 Spring-boot 后端——生成了一个 XSRF 令牌。不,理想,但如果这是正常的和预期的,那么我可以接受。转到登录页面时生成的唯一请求是“GET”请求。

在我登录到应用程序后,它会验证第一个 XSRF-TOKEN 并验证其有效性并继续登录。但是,在 Web 服务上更改 XSRF-TOKEN 后会立即生成一个新的 CSRF 令牌。因此,前端和后端现在不同步了。我不确定如何在成功登录后更新 XSRF-TOKEN 或防止其被更改,因为这似乎没有任何好处……至少从我所读到的内容来看。

网络安全

@Override
protected void configure(HttpSecurity http) throws Exception {
    CsrfHeaderFilter csrfHeaderFilter = new CsrfHeaderFilter();

    http.httpBasic()
        .authenticationEntryPoint(new AuthenticationFailureHandler())
        .and()
            .authorizeRequests()
            .antMatchers("List of API URI").permitAll()
            .anyRequest().authenticated();

    // Configurations for CSRF end points
    http.httpBasic()
        .authenticationEntryPoint(new AuthenticationFailureHandler())
        .and()
            .csrf()
            .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
        .and()
            .authorizeRequests()
            .antMatchers("Login API URI").permitAll()
        .and()
            .addFilterAfter(csrfHeaderFilter, CsrfFilter.class);

        // Logout configurations
        http.logout()
        .permitAll()
        .logoutSuccessHandler((new HttpStatusReturningLogoutSuccessHandler(HttpStatus.OK)));
}

csrf 部分是分开的,希望只有在使用该 URI 发送发布请求时才会生成 csrf 令牌。情况似乎并非如此。无论发送到后端的 URI 是什么,似乎都会调用 CSRF Header 过滤器。

CSRF Header Filter -- 必需,因为必须更新 cookie 的域以允许前端和后端访问 XSRF-TOKEN。

@Override
protected void doFilterInternal(HttpServletRequest request,
                                  HttpServletResponse response, FilterChain filterChain)
          throws ServletException, IOException {

    CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class
            .getName());

    if (csrf != null) {
      Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
      String token = csrf.getToken();
      if (cookie == null || (token != null && !token.equals(cookie.getValue()))) {
        cookie = new Cookie("XSRF-TOKEN", token);
        cookie.setPath("/");
        cookie.setDomain(<omitted>);
        response.addCookie(cookie);
      }
    }
    filterChain.doFilter(request, response);
  }

我相信我的过滤器的组织方式存在问题,但我已经尝试了各种方法,从将不同的 http.httpBasic() 部分组合到一个组中,到将 antIgnores 用于 csrf(),再到不使用 GET 请求处理 CSRF 令牌。任何指导或建议将不胜感激!

如果您还有其他需要,请告诉我,我会尽力提供。

谢谢!

4

1 回答 1

0

正如我怀疑过滤顺序存在问题一样。在 Spring-Boot Security 中建立了一个过滤器层次结构。需要在将值添加到 cookie 之前生成 XSRF-TOKEN。如果在生成新值之前将旧值添加到 Cookie 中,则前端和后端将不同步,直到执行浏览器刷新。

这就是我在过滤顺序末尾添加过滤器的原因。如果有人有更好的切入点,我会相应地更新它并更新这个答案以反映它。

@Override
protected void configure(HttpSecurity http) throws Exception {
CsrfHeaderFilter csrfHeaderFilter = new CsrfHeaderFilter();

http.httpBasic()
    .authenticationEntryPoint(new AuthenticationFailureHandler())
    .and()
        .authorizeRequests()
        .antMatchers("List of API URI").permitAll()
        .anyRequest().authenticated();

// Configurations for CSRF end points
http.httpBasic()
    .authenticationEntryPoint(new AuthenticationFailureHandler())
    .and()
        .csrf()
        .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
    .and()
        .authorizeRequests()
        .antMatchers("Login API URI").permitAll()
    .and()
        .addFilterAfter(csrfHeaderFilter, ExceptionTranslationFilter.class);

    // Logout configurations
    http.logout()
    .permitAll()
    .logoutSuccessHandler((new HttpStatusReturningLogoutSuccessHandler(HttpStatus.OK)));
}
于 2020-04-29T19:41:55.267 回答