Spring (Spring Boot) 如何向前端提供 CSRF 令牌? [英] How does Spring (Spring Boot) provide CSRF token to frontend?

查看:60
本文介绍了Spring (Spring Boot) 如何向前端提供 CSRF 令牌?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试为基于 Spring-Boot(特别是 WebFlux)的项目添加 CSRF 保护.

I am trying to add CSRF protection to a project which is based on Spring-Boot (particularly WebFlux).

到目前为止我所尝试的是低于安全配置.

What I have tried so far is below security configuration.

@Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {

    http.
        ...
        .and()
        .csrf()
        .csrfTokenRepository(CookieServerCsrfTokenRepository.withHttpOnlyFalse())
        .requireCsrfProtectionMatcher(
            new NegatedServerWebExchangeMatcher(
                new OrServerWebExchangeMatcher(
                    Arrays.asList(
                        ServerWebExchangeMatchers.pathMatchers(HttpMethod.POST, FORM_LOGIN_URL),
                        ServerWebExchangeMatchers
                            .pathMatchers(HttpMethod.GET, PERMISSION_ENDPOINT)
                    )
                )
            )
        )
        .accessDeniedHandler(new CustomHttpStatusServerAccessDeniedHandler(HttpStatus.FORBIDDEN))
        ...;

    return http.build();
}

但是当我尝试上述配置时,我看不到任何与从服务器推送到浏览器的 CSRF 令牌相关的内容.默认情况下不是被推送给客户端吗?如果是这样,向客户端(浏览器)提供 CSRF 令牌的更简洁的方法是什么?在哪个 spring 文件中提到了这一点.(我跟着这个 -> https://docs.spring.io/spring-security/site/docs/3.2.0.CI-SNAPSHOT/reference/html/csrf.html)

But when I tried above configuration, I could not see anything related to a CSRF token being pushed from server to browser. Is it not by default being pushed to clients? If so what would be the cleaner way to provide CSRF token to client (browser)? In which spring document this is mentioned. (I followed this one -> https://docs.spring.io/spring-security/site/docs/3.2.0.CI-SNAPSHOT/reference/html/csrf.html)

附言(希望以下信息对回答有用)

P.S. (hoping these following information are of any use for an answer)

  • Spring Boot Webflux 应用程序未提供我的登录表单.它由运行在不同域(不同 IP 和端口)上的 angular 应用程序提供服务.这就是为什么我在上面的配置中有一个 FORM_LOGIN_URL 常量,它用作 .loginPage(FORM_LOGIN_URL).我已经自定义了 .authenticationSuccessHandler() 以重定向到 PERMISSION_ENDPOINT 直到它按预期工作.
  • My login form is not being served by Spring Boot Webflux application. It is served by a angular application running on a different domain (different IP & Port). That is why I have a FORM_LOGIN_URL constant in above configuration, which is used as .loginPage(FORM_LOGIN_URL). I have customized the .authenticationSuccessHandler() to redirect to PERMISSION_ENDPOINT which worked as intended up until.

推荐答案

这部分文档有点少,但显然 csrf-token 不会被保存,除非您订阅结果.

This part is a bit poorly documented, but apparently the csrf-token wont be saved unless you subscribe to the result.

@Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {

   final CookieServerCsrfTokenRepository cookieServerCsrfTokenRepository = new CookieServerCsrfTokenRepository();
        cookieServerCsrfTokenRepository.setCookieHttpOnly(false);

    http.csrf()
            .csrfTokenRepository(cookieServerCsrfTokenRepository)
            .and()
            .cors()

             ...
}

// Add a tiny webfilter that just subscribes
@Bean
public WebFilter addCsrfToken() {
    return (exchange, next) -> exchange.<Mono<CsrfToken>>getAttribute(CsrfToken.class.getName())
                .doOnSuccess(token -> {}) // do nothing, just subscribe :/
                .then(next.filter(exchange));
}

如果您使用的是功能端点,上述解决方案效果很好.您还可以使用 @ControllerAdvice 方法.

the above solution works well if you are using functional endpoints. You can also use a @ControllerAdvice approach.

@ControllerAdvice
public class SecurityControllerAdvice {@ModelAttribute Mono<CsrfToken> csrfToken(ServerWebExchange exchange) {
        Mono<CsrfToken> csrfToken = exchange.getAttribute(CsrfToken.class.getName());
        return csrfToken.doOnSuccess(token -> exchange.getAttributes()
                .put(CsrfRequestDataValueProcessor.DEFAULT_CSRF_ATTR_NAME, token));
    }
}

github 上有一个关于这个的公开错误报告

There is an open bug report for this on github

CookieServerCsrfTokenRepository 不添加 cookie

这篇关于Spring (Spring Boot) 如何向前端提供 CSRF 令牌?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆