使用 spring SecurityWebFilterChain 如何禁用/阻止除少数已知路径外的所有非 https 请求

Posted

技术标签:

【中文标题】使用 spring SecurityWebFilterChain 如何禁用/阻止除少数已知路径外的所有非 https 请求【英文标题】:Using spring SecurityWebFilterChain how to disable/block all non-https requests except few known paths 【发布时间】:2020-11-06 04:48:20 【问题描述】:

我在 Spring Boot Webflux 应用程序中使用 Spring 安全性主要在 HTTPS 端口上提供流量。但是,作为一项操作要求,我需要在我的 Spring Boot 应用程序中支持几个非安全 REST API 路径,以进行健康检查等,这些路径也需要在 HTTP 上公开。

那么,除了使用SecurityWebFilterChain bean 的已知路径之外,我如何强制对 HTTPS 的所有请求?

这就是我定义 SecurityWebFilterChain bean 的方式:

@Configuration
@EnableWebFluxSecurity
public class SecurityConfig     
    @Bean
    SecurityWebFilterChain webFilterChain( ServerHttpSecurity http )
     throws Exception 
         return http 
            .authorizeExchange(exchanges -> exchanges
                    .anyExchange().permitAll()
                    .and()
                    .exceptionHandling()
                    .authenticationEntryPoint((exchange, exception) ->
                        Mono.error(exception))
                    )
            .csrf().disable()
            .headers().disable()
            .logout().disable()
            .build();
    

这显然不会按预期工作,因为它允许所有请求使用 HTTPHTTPS 方案,而 我希望始终强制执行 HTTPS,路径除外,例如/health.

请建议我需要对上述代码进行哪些更改才能完成此操作。

【问题讨论】:

【参考方案1】:

这是我想出解决这个问题的方法。我在.matchers( customMatcher ) 方法中调用自定义匹配器

@Configuration
@EnableWebFluxSecurity
public class SecurityConfig 

    private static final Set<String> UNSECURED = new HashSet<>( 
             Arrays.asList ( new String[]  "/health", "/heartbeat"  ) );

    @Bean
    SecurityWebFilterChain webFilterChain( final ServerHttpSecurity http )     
        return http
                .authorizeExchange(
                        exchanges -> exchanges
                        .matchers( this::blockUnsecured ).permitAll()
                        .and()
                        .exceptionHandling()
                        .authenticationEntryPoint(
                               (exchange, exception) -> Mono.error(exception))
                        )
                .csrf().disable()
                .headers().disable()
                .logout().disable()
                .httpBasic().disable()
                .build();
    

    Mono<MatchResult> blockUnsecured( final ServerWebExchange exchange )     
        // Deny all requests except few known ones using "http" scheme
        URI uri = exchange.getRequest().getURI();

        boolean invalid = "http".equalsIgnoreCase( uri.getScheme() ) &&
                !UNSECURED.contains ( uri.getPath().toLowerCase() );    
        return invalid ? MatchResult.notMatch() : MatchResult.match();    
    

不确定是否有更好的方法。

【讨论】:

我认为我对你的问题的理解是完全错误的。如果我错了,请纠正我,因为我不知道 webflux,如果有人通过 https 连接,他们不需要提供任何登录详细信息,他们可以访问系统。对吗? 是的,这是正确的,没有登录,因为此应用程序正在使用双向 TLS,并且客户端正在提供有效的密钥/证书对进行连接。 在我看来,我根本不会使用 spring security 来检查只允许通过 http 的一些 url。我会使用简单的 servlet filterinterceptor (我不知道它在 webflux 中叫什么,但始终扮演相同的角色)并精确检查您在自定义匹配器中所做的事情。感觉就像买车拆了才得到轮胎 太棒了。对我也有好处,因为我被介绍了 web Flux spring 安全 虽然这似乎可行,但这段代码几乎没有问题。 .containsendsWith 的糟糕替代品。有人可能会在调试时扯掉他的头发;)另外,getPath().toLowerCase 意味着 /abc/ABC 将被视为相同的 URI。 URI 区分大小写。正如我所建议的,您应该只使用执行器并在内部路由请求,同时保持整个网站仅服务于 https 方案。当您提供混合内容时,对 SEO 排名也有很大影响。【参考方案2】:

通过复制HttpsRedirectWebFilter 创建一个自定义过滤器,在该过滤器中,如果请求的 url 不是/health,您将对其进行修改,使其发送 401 而不是重定向

@Configuration
@EnableWebFluxSecurity
public class SecurityConfig     
    @Bean
    SecurityWebFilterChain springWebFilterChain( ServerHttpSecurity http )
     throws Exception 
         return http.addFilterAt(your-custom-https-filter, 
                                 SecurityWebFiltersOrder.HTTPS_REDIRECT)
                    .
                  ......
    

    

【讨论】:

感谢您的回答。但是Javadoc of ServerHttpSecurity 没有requiresChannel() 方法。 没关系。反馈是任何形式的反馈。有一个.redirectToHttps(),如果你使用那一秒过滤器会起作用吗? 是的,我玩过.redirectToHttps()。它执行302 重定向,这不是所需的行为。我更愿意发回 500401 以进行不安全访问。 因此,如果它强制执行https,但它通过重定向来实现,而不是使用它,您可以通过复制HttpsRedirectWebFilter 的代码来创建自定义过滤器。在该自定义过滤器中,如果不是 https,而不是重定向,您可以发送 401 请分享所有相关代码,以便我查看。

以上是关于使用 spring SecurityWebFilterChain 如何禁用/阻止除少数已知路径外的所有非 https 请求的主要内容,如果未能解决你的问题,请参考以下文章

spring基础之二-;Spring IOC基本使用

Spring学习-----Spring使用@Autowired注解自动装配

Spring-使用JAVA的方式配置Spring-代理模式

Spring使用指南 ~ 5Spring AOP 使用简介

Spring使用指南 ~ 5Spring AOP 使用简介

Spring Framework,Spring Security - 可以在没有 Spring Framework 的情况下使用 Spring Security?