Spring Boot 安全配置忽略允许的端点

Posted

技术标签:

【中文标题】Spring Boot 安全配置忽略允许的端点【英文标题】:Spring boot security configuration ignoring permitted endpoints 【发布时间】:2020-04-19 11:00:45 【问题描述】:

我正在尝试通过 JWT 获得 Spring Security 以使用应用程序。我已经阅读了许多教程和示例,但没有什么真正适合我的用例。我们不通过用户名/密码进行授权,我们使用 twilio 来验证手机号码,然后我想创建一个简单的 JWT 令牌,给定一个手机号码作为主题。我已经能够做到这一点

这是一个简单的端点,存在于 /api/v1/jwt

@GetMapping("/jwt")
    fun jwt(@RequestParam(value = "number", required = true) number: String): String? 

        val jwtToken = Jwts.builder().setSubject(number).claim("roles", "user").setIssuedAt(Date()).signWith(SignatureAlgorithm.HS256, Base64.getEncoder().encodeToString("secret".toByteArray())).compact()

        return jwtToken

    

返回一个有效的 JWT 令牌。

我的安全配置不再起作用,现在所有端点似乎都受到保护,

@Configuration
@EnableWebSecurity
class SecurityConfig : WebSecurityConfigurerAdapter() 

    @Bean
    override fun authenticationManagerBean(): AuthenticationManager 
        return super.authenticationManagerBean()
    

    override fun configure(web: WebSecurity) 
        web.ignoring().antMatchers("/v2/api-docs",
                "/configuration/ui",
                "/swagger-resources/**",
                "/configuration/security",
                "/swagger-ui.html",
                "/webjars/**");
    

    override fun configure(http: HttpSecurity) 

        http.csrf()
                .disable()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                .antMatchers("/api/v1/auth/**").permitAll()
                .anyRequest().authenticated()
                .and()
                .addFilterBefore(JwtFilter(), UsernamePasswordAuthenticationFilter::class.java)
    

JWT 过滤器


    @Throws(IOException::class, ServletException::class)
    override fun doFilter(req: ServletRequest, res: ServletResponse, chain: FilterChain) 
        val request = req as HttpServletRequest
        val response = res as HttpServletResponse
        val authHeader = request.getHeader("authorization")
        if ("OPTIONS" == request.method) 
            response.status = HttpServletResponse.SC_OK
            chain.doFilter(req, res)
         else 
            if (authHeader == null || !authHeader.startsWith("Bearer ")) 
                throw ServletException("Missing or invalid Authorization header")
            
            val token = authHeader.substring(7)
            try 
                val claims = Jwts.parser().setSigningKey(Base64.getEncoder().encodeToString("secret".toByteArray())).parseClaimsJws(token).body
                request.setAttribute("claims", claims)
             catch (e: SignatureException) 
                throw ServletException("Invalid token")
            
            chain.doFilter(req, res)
        
    

似乎过滤器随时都会被击中,不管它上面的 permitall 是什么。 过滤器不应该在任何 api/v1/auth/ 路径上被忽略吗?我想我错过了什么。

第二个问题是有没有一种方法可以应用这个过滤器而不必在之前或之后添加并且不扩展https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/authentication/AbstractAuthenticationProcessingFilter.html

编辑:antPathRequestMatcher 没有触发配置,但我什至添加了 websecurity 配置的路径,我得到了这个日志

2019-12-30 14:44:44.792 DEBUG 81181 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy        : /api/v1/auth/request?number=5555555 has an empty filter list```

【问题讨论】:

如果不被允许,您的路径不正确。为 Spring Security 启用日志记录,它会在请求该端点时准确显示匹配的路径。对于您的第二个问题,不,这是不可能的,有不同的选择,但您必须以相同的方式将它们插入安全链。 看起来它并没有试图查看来自 httpSecurity only webSecurity 的任何匹配器。我一定是建错了?? 获取这些日志太疯狂了2019-12-30 14:44:44.792 DEBUG 81181 --- [nio-8080-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/api/v1/auth/request'; against '/api/v1/auth/request' 2019-12-30 14:44:44.792 DEBUG 81181 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /api/v1/auth/request?number=5555555555 has an empty filter list 您的规则说允许“/api/v1/auth/**”之后的所有内容,并且任何其他请求都需要身份验证,因为您说您的 JWT 端点是“/api/v1/jwt” ",这意味着您的 JWT 端点也需要身份验证。 “/api/v1/auth/request”不受保护,或任何在“auth/**”之后的内容。 控制器被映射为``` @RestController @RequestMapping("/api/v1/auth") class AuthController : MainController() ``` 所以完整路径是 api/v1/ auth/jwt 所以它不应该命中过滤器 【参考方案1】:

在您的配置中,您有:

override fun configure(http: HttpSecurity) 
  http.csrf()
  .disable()
  .sessionManagement()
  .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
  .and()
  .authorizeRequests()
  .antMatchers("/api/v1/auth/**").permitAll()
  .anyRequest().authenticated()
  .and()
  .addFilterBefore(JwtFilter(), UsernamePasswordAuthenticationFilter::class.java)

我看到以下内容:

.antMatchers("/api/v1/auth/**").permitAll()
.anyRequest().authenticated()

因此 Spring Security 正在检查所有请求的身份验证。 在我的 spring 配置中,我通常会这样做:

.antMatchers("/swagger-ui.html","/webjars/**","/swagger-resources/**", "/v2/**","/csrf")
.permitAll()
.antMatchers("/**")
.authenticated()

所以尝试通过设置来改变你的配置:

override fun configure(http: HttpSecurity) 
  http.csrf()
  .disable()
  .sessionManagement()
  .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
  .and()
  .authorizeRequests()
  .antMatchers("/api/v1/auth/**").permitAll()
  .antMatchers("/**").authenticated()
  .and()
  .addFilterBefore(JwtFilter(), UsernamePasswordAuthenticationFilter::class.java)

关于你的第二个问题:

第二个问题有没有办法应用这个过滤器而不必 在之前或之后添加并且不扩展 https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/authentication/AbstractAuthenticationProcessingFilter.html

在这种情况下,老实说,我会通过使用 spring security 和 spring security oauth sprign security jwt 来继续 OAuth/OpenID。

在这种情况下,我将创建一个 ResourceServer 配置类和一个 AuthorizationServer 配置类(或者同一个类可以用作 AuthorizationServer 和 ResourceServer);一个很好的例子在这里https://www.baeldung.com/spring-security-oauth-jwt

希望对你有用

安杰洛

【讨论】:

【参考方案2】:

您可以使用configure(web: WebSecurity),它将绕过弹簧安全过滤器并且可以公开访问端点。

override fun configure(web: WebSecurity) 
        web.ignoring().antMatchers("/api/v1/auth/**",
                "/v2/api-docs",
                "/configuration/ui",
                "/swagger-resources/**",
                "/configuration/security",
                "/swagger-ui.html",
                "/webjars/**");
    

您可以使用configure(http: HttpSecurity) 进行会话管理和基于角色的身份验证。你可能会看到HttpSecurity vs WebSecurity。

对于具有@Component(或任何风格的@Bean)的自定义过滤器,WebSecurityConfigurerAdapter 将告诉 Spring Security 忽略通过它添加的任何过滤器。然后过滤器仍然被调用,因为@Component(或任何形式的@Bean)注释告诉Spring(再次)将过滤器添加到安全链之外。因此,当过滤器在安全链中被忽略时,它并没有被另一个(非安全?)链忽略。 (See Here)

【讨论】:

这加上删除 HttpSecurity 上的任何 antmatchers 都有效【参考方案3】:

工作示例

@EnableWebSecurity
class SecurityConfig() : WebSecurityConfigurerAdapter() 

    @Autowired
    lateinit var tokenService: TokenService

    override fun configure(web: WebSecurity) 
        web.ignoring().antMatchers("/v2/api-docs",
                "/configuration/ui",
                "/swagger-resources/**",
                "/configuration/security",
                "/swagger-ui.html",
                "/webjars/**","/api/v1/auth/**");
    

    override fun configure(http: HttpSecurity) 
        http.cors().and().csrf()
                .disable()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .addFilterBefore(JwtFilter(tokenService), UsernamePasswordAuthenticationFilter::class.java)


    

【讨论】:

以上是关于Spring Boot 安全配置忽略允许的端点的主要内容,如果未能解决你的问题,请参考以下文章

来自文件的 Spring Boot http 安全 jwt 密钥

Spring:使用 Spring Security 为执行器端点配置安全性

Spring:使用Spring Security配置执行器端点的安全性

无法访问 Spring Boot 中的不安全端点

启用具有 JWT 安全性的 Spring Boot 2.0 执行器端点

在aws上忽略基于url到spring boot 2应用程序的黑客攻击是不是安全?