Spring security StrictHttpFirewall 不验证标头

问题描述 投票:0回答:1

我正在尝试添加自定义 StrictHttpFirewall,以便能够在标头与我的模式不匹配的情况下拒绝请求。

我的 Spring security 配置如下:

@Configuration
@EnableWebSecurity
class SecurityConfig {

    companion object {
        private val HEADER_NAME_PATTERN = "^[a-z1-9_-]{1,512}$".toRegex(RegexOption.IGNORE_CASE)
        private val HEADER_VALUE_BASE_PATTERN = "[\\p{IsAssigned}&&[^\\p{IsControl}]]*".toRegex()
        private val HEADER_VALUE_ERROR_PATTERN = "[<>]".toRegex()
    }

    @Bean
    fun requestRejectedHandler(): RequestRejectedHandler = ErrorResponseRequestRejectedHandler()

    @Bean
    fun httpFirewall(): HttpFirewall {
        val firewall = StrictHttpFirewall()
        val headerNames = { header: String -> HEADER_NAME_PATTERN.matches(header) }
        val headerValues = { value: String ->
            HEADER_VALUE_BASE_PATTERN.containsMatchIn(value).and(
                !HEADER_VALUE_ERROR_PATTERN.containsMatchIn(value)
            )
        }
        firewall.setAllowedHeaderNames(headerNames)
        firewall.setAllowedHeaderValues(headerValues)
        firewall.setAllowedHttpMethods(
            listOf(GET.name(), POST.name(), PUT.name(), PATCH.name(), DELETE.name())
        )
        return firewall
    }

    @Bean
    @Throws(Exception::class)
    fun filterChain(http: HttpSecurity): SecurityFilterChain =
        http
            .authorizeHttpRequests { it.anyRequest().permitAll() }
            .sessionManagement {
                it
                    .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                    .disable()
            }
            .headers {
                it
                    .frameOptions { option -> option.sameOrigin() }
                    .xssProtection(Customizer.withDefaults())
                    .cacheControl { cache -> cache.disable() }
                    .contentSecurityPolicy(Customizer.withDefaults())
            }
            .cors { it.disable() }
            .csrf { it.disable() }
            .requestCache { it.disable() }
            .build()
}

但不幸的是它不起作用,我仍然能够传递与我的正则表达式不匹配的标头。 我有一个很长的调试会话,它看起来像请求本身(由mockMVC制作)具有所有标头,但 spring security 不会检查请求本身的标头。有趣的是:它正在验证我在控制器方法参数级别上指定为强制的标头 - 例如 @RequestHeader(value = "my-header", required = true)。如果有任何帮助,我们将不胜感激。

已经尝试过:

  1. 将 httpFirewall 显式设置为 WebSecurity - 没有成功
  2. 添加了自定义过滤器来调试标头,因为结果标头名称已验证,但只是因为我显式调用了
    request.headerNames.toList()
    因为请求本身是用 HttpFirewallRequest 实现在内部包装的,它已经用我实际期望的验证覆盖了方法
    getHeaders
  3. 不仅向
    mockMvc
    提出请求,还向
    RestTemplate
    提出请求,并且仅通过邮递员提出请求 - 没有成功
java kotlin spring-security request-headers
1个回答
0
投票

StrictHttpFirewall
检查标头,但懒惰地。另外,您必须注意到
StrictHttpFirewall
将请求和响应都包装到
Wrapper
中。

有了这个,

StrictHttpFirewall
实际上不会拒绝请求,除非在
filterChain
下发出访问黑名单标头之一的请求。这意味着即使您有一个列入黑名单的标头,但过滤器链或控制器中没有人尝试读取该标头,您的请求在尝试读取之前不会被拒绝。

在引入此类保护的 PR 中,进行了与此类标头检查的性能相关的讨论,因为此检查将执行多次。

为了满足您的要求,我认为

StrictHttpFirewall
无法解决此问题。要急切地拒绝请求,您必须编写一个位于过滤器链开头或 mvc 层的过滤器,检查是否存在此类标头并拒绝它。

通过在过滤器链中引入请求可以获得的一个优势是

FilterChainProxy
接受一个
RequestReject(ed)Handler
,如果您选择抛出它,它将能够处理
RequestReject(ed)Exception

© www.soinside.com 2019 - 2024. All rights reserved.