我想在 webflux/kotlin/spring boot 3 应用程序中禁用 webhook 端点的 CSRF

I want to disable CSRF for a webhook endpoint in webflux/kotlin/spring boot 3 app

提问人:Shaunyl 提问时间:11/3/2023 最后编辑:Shaunyl 更新时间:11/8/2023 访问量:43

问:

我有以下代码:

@Bean
fun configure(http: ServerHttpSecurity): SecurityWebFilterChain {
    // @formatter:off
    return http
        .authorizeExchange { it.pathMatchers(GET, *ALLOW_LIST_STATIC_RESOURCES).permitAll() }
        .authorizeExchange { it.pathMatchers(GET, *ALLOW_LIST_VIEWS).permitAll() }
        .authorizeExchange { it.pathMatchers(GET, *ALLOW_LIST_RESOURCES).permitAll() }
        .authorizeExchange { it.pathMatchers(POST, *ALLOW_LIST_API_POST).permitAll() }
        .authorizeExchange { it.pathMatchers(DELETE, *ALLOW_LIST_API_DELETE).permitAll() }
        .formLogin { it.disable() }
        .headers { headers -> headers.contentTypeOptions { } }
        .headers { headers -> headers.frameOptions { it.mode(XFrameOptionsServerHttpHeadersWriter.Mode.DENY) } }
        .headers { headers -> headers.xssProtection { it.disable() } }
        .headers { headers -> headers.permissionsPolicy { it.policy("accelerometer=(), ambient-light-sensor=(), autoplay=(), camera=(), encrypted-media=(), fullscreen=(), geolocation=(), gyroscope=(), interest-cohort=(), magnetometer=(), microphone=(), midi=(), payment=(), usb=(), vr=(), xr-spatial-tracking=()") } }
        .headers { headers -> headers.contentSecurityPolicy { it.policyDirectives(contentSecurityPolicy) } }
        .build()
    // @formatter:on
}

我只想为端点“/app/webhook”禁用 CSRF 保护,但我找不到方法。 我不能做:因为不存在。 我该怎么做?我希望 CSRF 适用于除该端点之外的所有端点。我认为 Spring 默认对所有修改调用(不包括 GET)应用 CSRF 保护,因此这些 webhook 调用将被阻止,因为它们来自外部提供商。 内部使用也不起作用。.csrf { it.ignoringAntMatchers("/app/webhook") }ignoringAntMatchersNegatedServerWebExchangeMatchercsrf.requireCsrfProtectionMatcher

感谢您的帮助。

编辑1

如果我使用此代码:

.csrf { csrf -> 
csrf.requireCsrfProtectionMatcher(disabledUrlForCSRF()) }.build()

fun disabledUrlForCSRF(): AndServerWebExchangeMatcher = AndServerWebExchangeMatcher(
    CsrfWebFilter.DEFAULT_CSRF_MATCHER,
    NegatedServerWebExchangeMatcher(
        ServerWebExchangeMatchers.pathMatchers(POST, "/app/webhook")
    )

它有效

编辑2

我也通过这样写它来使它工作(为了清楚起见,稍微清理了一下):

@Bean
fun configure(http: ServerHttpSecurity): SecurityWebFilterChain {
    // @formatter:off
    return http
        .securityMatcher(
            isNot(  ServerWebExchangeMatchers.pathMatchers(POST,"/app/webhook")
            )
        )
        .authorizeExchange { it.pathMatchers(OPTIONS).permitAll() }
        .authorizeExchange { it.pathMatchers(POST, *ALLOW_LIST_API_POST).permitAll() }
        .authorizeExchange { it.pathMatchers(DELETE, *ALLOW_LIST_API_DELETE).permitAll() }
        .authorizeExchange { it.pathMatchers(GET).permitAll() }
        .authorizeExchange { it.anyExchange().denyAll() }
        .httpBasic { it.disable() }
        .formLogin { it.disable() }.securityContextRepository(NoOpServerSecurityContextRepository.getInstance())
        .build()
    // @formatter:on
}

fun isNot(matcher: ServerWebExchangeMatcher): ServerWebExchangeMatcher {
    return NegatedServerWebExchangeMatcher(matcher)
}

这里有三件重要的事情:

  • 如果启用了 CSRF(因此没有 csrf.disable()),即使我明确告诉他不要使用 NoOpServerSecurityContextRepository 这样做,它也会创建一个 SESSION cookie。
  • 我添加了所有端点上的 GET 匹配器,以将用户重定向到自定义错误页面,以防用户浏览到不存在的页面,例如,仅使用该行时不会发生这种情况。permitAll()anyExchange().denyAll()

但这些与主题无关。

谢谢。

kotlin spring-security、 spring-webflux csrf

评论

1赞 Steve Riesenberg 11/4/2023
您如何进行身份验证?您已显式禁用(不需要这样做),但尚未指定身份验证机制。另外,您知道 Kotlin DSL 吗?它会清理并使您的代码在语义上正确,但现在看起来并非如此。formLogin()
0赞 Shaunyl 11/4/2023
是的,我知道,但我对我所编码的内容感到满意。该应用程序没有身份验证,所有用户都是匿名的。我不需要身份验证,但这对手头的主题无关紧要
0赞 Steve Riesenberg 11/6/2023
好的,使用否定匹配器,你演示了工作。因此,如果您能提供完整的样本,我可以仔细查看,但根据您在此处提供的内容,我无法重现。
0赞 Shaunyl 11/8/2023
我更新了问题。使用前面的代码,我在不希望应用 csrf 保护的唯一端点上得到 FORBIDDEN,因此显然 Negated 过滤器不会过滤掉该端点。无论如何,我已经用一个有效的解决方案更新了这个问题,但老实说,我不确定它是否安全,是否是最佳实践,因为我不是安全专家。
0赞 Shaunyl 11/8/2023
好吧,我现在明白你的意思了,我允许 /wehbook/app 而不是 /app/webhook,错误确实在我这边。因此,确实第一个解决方案也有效。

答: 暂无答案