如何绕过特定域的经过身份验证的端点上的弹簧安全性?

Posted

技术标签:

【中文标题】如何绕过特定域的经过身份验证的端点上的弹簧安全性?【英文标题】:How to bypass spring security on an authenticated endpoint for specific domain? 【发布时间】:2021-09-07 12:47:14 【问题描述】:

我正在使用基于 jwt 令牌的 Spring Security。 我有一个需要身份验证的端点“/sample-endpoint”。但是,当请求来自名为 xyz.com 的特定域时,我需要绕过此端点的安全性。

可以这样做吗?如果是这样,该怎么做?

这是我目前所拥有的。

安全配置

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter 

// cant add the end point here as it would open up for everybody.
public static final String[] unauthedUrls =  "healthcheck","some-other-endpoint"  

@Override
    protected void configure(HttpSecurity http) throws Exception 
        
        http
                .httpBasic()
                .disable()
                .csrf()
                .disable()
                .cors()
                .and()
                .headers().frameOptions()
                .disable()
                .and()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .exceptionHandling()
                .authenticationEntryPoint(jwtAuthenticationEntryPoint)
                .and()
                .addFilterAfter(jwtSecurityFilter, UsernamePasswordAuthenticationFilter.class)
                .authorizeRequests()
                .antMatchers(unauthedUrls)
                .permitAll()
                .anyRequest()
                .authenticated();
    

这里是 JwtSecurityFilter 的实现。

public class JwtSecurityFilter extends OncePerRequestFilter 

    private static final Logger LOGGER = LoggerFactory.getLogger(JwtSecurityFilter.class);

    private static final String JWT_PREFIX = "Bearer ";

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException 
        setAuthenticationContext(request);

        chain.doFilter(request, response);
    

    private void setAuthenticationContext(HttpServletRequest request) 
        try 
            String token = getJwt(request);

            if (StringUtils.isBlank(token)) 
                throw new RuntimeException("Authorization token not provided");
            

 

// some logic here...
         catch (Exception ex) 
      
            if (request != null && Arrays.stream(SecurityConfig.unauthedUrls).anyMatch(url -> request.getRequestURI().contains(url))) 
                // it's a URL that isn't authenticated so an exception here is normal
                // if we couldn't get a token
                return;
            
            LOGGER.warn("Unable to authenticate request:  ", ex.getMessage(), request == null ? null : request.getRequestURI());
        
    

    private String getJwt(HttpServletRequest request) 

        String authHeader = request.getHeader(HttpHeaders.AUTHORIZATION);

        if (StringUtils.isBlank(authHeader) || !authHeader.startsWith(JWT_PREFIX)) 
            return "";
        

        return authHeader.replaceFirst(Pattern.quote(JWT_PREFIX), "");
    



【问题讨论】:

欢迎来到 SO。也许您可以创建一个自定义表达式处理程序来检查 HttpServletRequest。类似.expressionHandler(new CustomDomainCheckExpressionHandler()).anyRequest().access("isDomainWhitelisted()") 【参考方案1】:

您想要忽略某些 URL,因为它会覆盖接受 WebSecurity 对象并忽略模式的配置方法。比如使用api:

@Override
public void configure(WebSecurity web) throws Exception 
    web.ignoring().antMatchers("/api/v1/signup");

并从 HttpSecurity 部分中删除该行。这将告诉 Spring Security 忽略此 URL,并且不对它们应用任何过滤器。

我有更好的办法:

http
    .authorizeRequests()
    .antMatchers("/api/v1/signup/**").permitAll()
    .anyRequest().authenticated()

【讨论】:

这将为所有人打开这个端点。我想保持该端点对所有人关闭,而只对特定域开放。 另外,请不要复制粘贴其他帖子的答案。 ***.com/questions/30366405/… @troy 欢迎来到 SO。查看内置表达式,例如hasIpAddress。见Web Security Expressions。我们需要这样的东西来检查请求域/主机。

以上是关于如何绕过特定域的经过身份验证的端点上的弹簧安全性?的主要内容,如果未能解决你的问题,请参考以下文章

Spring安全缓存基本身份验证?不验证后续请求

弹簧安全过滤器没有启动

如何禁用特定端点的身份验证?

MobileFirst 身份验证框架是不是提供任何选项来显式绕过特定资源的安全检查?

安全域的 Wildfly 刷新缓存

如何从控制器调用身份验证 - 弹簧安全核心插件