CsrfFilter 在 Spring 6.0+ 中总是引​​发异常

use*_*289 5 spring spring-security angularjs spring-boot csrf-token

在新的 Spring Boot 3.0.1 中,我通过按照 Spring 文档添加以下简单配置来添加对 CSRF 保护的支持:

http.csrf().csrfTokenRepository(tokenRepository);
Run Code Online (Sandbox Code Playgroud)

 @Bean
    public CsrfTokenRepository tokenRepository() {
        var tokenRepo = CookieCsrfTokenRepository.withHttpOnlyFalse();
        tokenRepo.setCookiePath("/");
        return tokenRepo;
    }
Run Code Online (Sandbox Code Playgroud)

在前端,有一个导入标准库的 Angular 应用程序

import {HTTP_INTERCEPTORS, HttpClientModule, HttpClientXsrfModule} from '@angular/common/http';
Run Code Online (Sandbox Code Playgroud)

但是我无法让它与标准工作流程一起工作,例如

  1. 执行请求以从服务器获取 XCSRF-TOKEN cookie。
  2. 从 cookie 中提取令牌值。
  3. 添加 X-XSRF-TOKEN 标头以及从 cookie 中提取的值。

前端发送具有相同令牌值的 cookie 和 header,但检查失败:

public final class XorCsrfTokenRequestAttributeHandler ...

private static String getTokenValue(String actualToken, String token) {
        byte[] actualBytes;
        try {
            actualBytes = Base64.getUrlDecoder().decode(actualToken);
        }
        catch (Exception ex) {
            return null;
        }

        byte[] tokenBytes = Utf8.encode(token);
        int tokenSize = tokenBytes.length;
        if (actualBytes.length < tokenSize) {
            return null;
        }
Run Code Online (Sandbox Code Playgroud)

这些方法始终返回 null

if (actualBytes.length < tokenSize) {
            return null;
        }
Run Code Online (Sandbox Code Playgroud)

使其工作的唯一方法是通过添加端点返回要直接粘贴到标头中的编码字符串,如下所示:

 DeferredCsrfToken deferredCsrfToken = repository.loadDeferredToken(request, response);
        requestHandler.handle(request, response, deferredCsrfToken::get);
        CsrfToken csrfToken = (CsrfToken) request.getAttribute("_csrf");
        return csrfToken.getToken();
Run Code Online (Sandbox Code Playgroud)

因此,要在标头中使用的返回值如下所示:

ab5tfqabXomGPuLjDQk96mVMZHNOh_JnpPVM4F_hQU1sOMyWW9sLSsCtb72rWNPabyQJ01EpSUsvtctKwcQphWeAJX9ZDPmg
Run Code Online (Sandbox Code Playgroud)

代替

5adaf830-40e6-43c9-b42a-e36fd713c1a6
Run Code Online (Sandbox Code Playgroud)

对我在这里缺少什么有什么建议吗?

小智 2

Spring Security 6 改变了一些事情。

迁移指南还提到了在客户端使用 Angular 和 HttpClientXsrfModule 或类似方法时需要注意的更改。

https://docs.spring.io/spring-security/reference/5.8/migration/servlet/exploits.html#_i_am_using_angularjs_or_another_javascript_framework

https://docs.spring.io/spring-security/reference/migration/servlet/exploits.html

根据 Spring Security 迁移指南,以下配置应该有效,并且是推荐的方式。

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    CookieCsrfTokenRepository tokenRepository = CookieCsrfTokenRepository.withHttpOnlyFalse();
    CsrfTokenRequestAttributeHandler requestHandler = new CsrfTokenRequestAttributeHandler();
    // (optional) set null to opt out of deferred tokens
    requestHandler.setCsrfRequestAttributeName(null);

    http
        // ...
        .csrf((csrf) -> csrf
            .csrfTokenRepository(tokenRepository)
            .csrfTokenRequestHandler(requestHandler)
        );

    return http.build();
}
Run Code Online (Sandbox Code Playgroud)

有关更多详细信息,请阅读迁移指南,以便您可以适应您的需求。