spring-security 三种情况下的认证绕过

0x01: antMatchers 配置认证绕过

问题概览:

当使用 antMatchers 配合 spring-webmvc 这个常见搭配使用时,如果代码编写考虑不周,比如使用以下 spring-security 配置保护 /test 路由:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf().disable()
                .authorizeRequests()
                .antMatchers("/test").access("hasRole('ADMIN')")
                .antMatchers("/**").permitAll();
        super.configure(http);
    }

}

/test 路由对应的 TestController:

@RestController
public class TestController {
    @RequestMapping(value = "/test", method = {RequestMethod.GET, RequestMethod.POST})
    public Object test(){
        return "ok";
    }
}

此时由于 spring-webmvc 组件 spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMapping.java 代码中的 useTrailingSlashMatch 选项默认为 true,导致攻击者可以访问 /test/ 路由绕过 spring-security/test 路由的保护,直接访问到 TestController 的效果。

漏洞存在于最新版(5.4.6) spring-security-webspring-webmvc (5.3.6) 的配合使用中,复测可使用如下配置:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.4.5</version>
</parent>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
</dependencies>

漏洞修复:

使用适配 spring-webmvc 组件的 MvcRequestMatcher 写法 mvcMatchers("/test").access("hasRole('ADMIN')") 或者使用 antMatchers("/test/**").access("hasRole('ADMIN')") 写法防止认证绕过。

个人点评:

这个安全问题我报告给了官方,但是官方回复说提供了 MvcRequestMatcher 写法来防止这个问题,官方文档有参考,不考虑是个安全问题。后面我仔细看了下,发现上面的漏洞,包括增加 MvcRequestMatcher 写法都是 cve-2016-5007 漏洞修复后的延伸

github 搜索几种不同 RequestMatcher 代码写法片段的数量:

可见 antMatchers 的使用占据绝对的优势,官方网站提供的 MvcRequestMatcher 写法使用量并不大。如果开发者一不注意,像示例中用 spring-security 匹配 /test 路由时在antMatchers规则中写成 /test而不是 /test/** ,那么就可能存在认证绕过漏洞。

0x02: regexMatchers 配置认证绕过

问题概览:

关键代码在 spring-security-web org.springframework.security.web.util.matcher.RegexRequestMatcher.java 类 matches 方法:

public boolean matches(HttpServletRequest request) {
    if (this.httpMethod != null && request.getMethod() != null && this.httpMethod != valueOf(request.getMethod())) {
        return false;
    } else {
        String url = request.getServletPath();
        String pathInfo = request.getPathInfo();
        String query = request.getQueryString();
        if (pathInfo != null || query != null) {
            StringBuilder sb = new StringBuilder(url);
            if (pathInfo != null) {
                sb.append(pathInfo);
            }

            if (query != null) {
                sb.append('?').append(query);
            }

            url = sb.toString();
        }

        logger.debug(LogMessage.format("Checking match of request : '%s'; against '%s'", url, this.pattern));
        return this.pattern.matcher(url).matches();
    }
}

request.getServletPath 获得 url 路径后,还会尝试把 ? 和后面的参数拼接上去,作为 url,然后用 this.pattern.matcher(url).matches() 去和 spring-security-web 配置的 pattern 匹配。

此时,如果配置的 regex pattern 有问题,比如对下面/test 路由对应的 TestController:

@RestController
public class TestController {
    @RequestMapping(value = "/test", method = {RequestMethod.GET, RequestMethod.POST})
    public Object test(){
        return "ok";
    }
}

对于下面的几种匹配规则,当请求 /test? 路径时,上面 matches 方法中的 url 参数值都会是/test?,导致认证绕过:

.regexMatchers("/test").access("hasRole('ADMIN')")
.regexMatchers("/test/").access("hasRole('ADMIN')")
.regexMatchers("/test/*").access("hasRole('ADMIN')")
.regexMatchers("/test/.*").access("hasRole('ADMIN')")

漏洞修复:

换下面的正则匹配即可:

.regexMatchers("/test.*?").access("hasRole('ADMIN')")

个人点评:

regexMatchers 使用量比较小,不过要是开发者想当然的用错误正则去匹配以为的 url 路径,就会导致意外的认证绕过漏洞。

0x03: useSuffixPatternMatch 低版本认证绕过

问题概览:

低版本 的 spring-webmvc 及其相关组件,包括:

spring-webmvc <= 5.2.4.RELEASE
spring-framework <= 5.2.6.RELEASE
spring-boot-starter-parent <= 2.2.5.RELEASE

在代码中定义的 useSuffixPatternMatch 配置默认值为 true ,表示使用后缀匹配模式匹配路径。

/path/abc 路由也会允许 /path/abcd.ef/path/abcde.f 等增加 .xxx 后缀形式的路径匹配成功。

漏洞修复:

使用高版本的 spring-webmvc 能有效避免问题。

个人点评:

在低版本 spring-webmvc 下十分好用。

标签   

评论