我正在尝试添加自定义 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)。如果有任何帮助,我们将不胜感激。
已经尝试过:
request.headerNames.toList()
因为请求本身是用 HttpFirewallRequest 实现在内部包装的,它已经用我实际期望的验证覆盖了方法 getHeaders
。mockMvc
提出请求,还向RestTemplate
提出请求,并且仅通过邮递员提出请求 - 没有成功StrictHttpFirewall
检查标头,但懒惰地。另外,您必须注意到 StrictHttpFirewall
将请求和响应都包装到 Wrapper
中。
有了这个,
StrictHttpFirewall
实际上不会拒绝请求,除非在filterChain
下发出访问黑名单标头之一的请求。这意味着即使您有一个列入黑名单的标头,但过滤器链或控制器中没有人尝试读取该标头,您的请求在尝试读取之前不会被拒绝。
在引入此类保护的 PR 中,进行了与此类标头检查的性能相关的讨论,因为此检查将执行多次。
为了满足您的要求,我认为
StrictHttpFirewall
无法解决此问题。要急切地拒绝请求,您必须编写一个位于过滤器链开头或 mvc 层的过滤器,检查是否存在此类标头并拒绝它。
通过在过滤器链中引入请求可以获得的一个优势是
FilterChainProxy
接受一个RequestReject(ed)Handler
,如果您选择抛出它,它将能够处理RequestReject(ed)Exception
。