Spring Boot CloudFoundry Actuator 认证绕过漏洞 CVE-2026-22733
字数 4429
更新时间 2026-04-15 12:08:06

Spring Boot CloudFoundry Actuator 认证绕过漏洞 (CVE-2026-22733) 教学文档

1. 漏洞信息

漏洞标识:CVE-2026-22733
漏洞类型:认证绕过
影响组件:Spring Boot CloudFoundry Actuator
漏洞等级:高危

2. 受影响版本

漏洞影响多个Spring Boot主版本系列,具体如下:

  • Spring Boot 4.x 系列:4.0.0 至 4.0.3
  • Spring Boot 3.x 系列
    • 3.5.0 至 3.5.11
    • 3.4.0 至 3.4.14
    • 3.3.0 至 3.3.17
  • Spring Boot 2.x 系列:2.7.0 至 2.7.31
    • 注意:2.7.9 版本有部分改进,但漏洞依然存在,直到 2.7.32 才完全修复。

3. 漏洞描述

3.1 根本原因

此漏洞的根本原因是 Spring CloudFoundry Actuator 自动配置中的安全配置与 Spring MVC 的请求处理机制(HandlerMapping)之间存在安全缺陷,导致配合不当,形成认证绕过。

3.2 漏洞触发条件

  1. 应用环境:应用必须运行在(或配置为运行在)CloudFoundry 平台环境中,这通常通过设置 spring.main.cloud-platform=CLOUD_FOUNDRY 属性来激活 CloudFoundry 相关的自动配置。
  2. 配置:必须启用了 Spring Security 和 Actuator,并且 CloudFoundry Actuator 功能被启用 (management.cloudfoundry.enabled=true, 通常由上述平台条件触发)。
  3. 代码:存在将自定义控制器(Controller)映射到 /cloudfoundryapplication/** 路径下的情况。

3.3 漏洞机制

漏洞的形成涉及三个关键环节的连锁反应:

环节一:Spring Security 的过度忽略

  • CloudFoundryActuatorAutoConfiguration 会自动配置一个 IgnoredCloudFoundryPathsWebSecurityCustomizer 组件。
  • 在受影响版本(如 2.7.0-2.7.8)中,此组件会调用 web.ignoring().requestMatchers(new AntPathRequestMatcher(“/cloudfoundryapplication/**“))
  • 后果web.ignoring() 会让 Spring Security 的安全过滤器链(Security FilterChain)完全忽略对 /cloudfoundryapplication/** 路径下所有请求的安全检查,包括认证和授权。请求会直接“穿过”安全层。

环节二:CloudFoundry 的 HandlerMapping 未完全覆盖

  • 对于 /cloudfoundryapplication/** 路径的请求,Spring MVC 会首先交由 CloudFoundryWebEndpointServletHandlerMapping 尝试处理。
  • 问题:这个 HandlerMapping 只会处理真正在 CloudFoundry Actuator 中注册过的端点(例如 /cloudfoundryapplication/health)。对于该路径下的、未在 CloudFoundry 注册的端点(例如自定义的 /cloudfoundryapplication/admin),此 HandlerMapping 会返回 null,表示无法处理。
  • 后果:请求会继续向下传递给其他 HandlerMapping。

环节三:请求落入自定义控制器

  • RequestMappingHandlerMapping(负责处理普通 @Controller@RestController)收到请求时,它会成功匹配到开发者自定义的、映射在 /cloudfoundryapplication/admin 的控制器方法。
  • 后果:由于请求已在环节一被 Spring Security 忽略,因此无需任何认证即可直接执行业务逻辑,返回敏感数据,造成认证绕过。

总结漏洞链
Spring Security 完全忽略路径 -> CloudFoundry专属HandlerMapping不处理未知端点 -> 普通HandlerMapping处理自定义端点 -> 认证被绕过

4. 环境搭建与验证

4.1 关键依赖配置 (Maven)

创建一个 Spring Boot 2.7.8 的项目(用于复现原始漏洞),pom.xml 关键依赖如下:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.7.8</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>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
</dependencies>

4.2 关键应用配置

application.properties 中必须包含以下配置以触发漏洞:

server.port=8080
# 关键配置:模拟或指定应用运行在CloudFoundry平台,激活漏洞相关自动配置
spring.main.cloud-platform=CLOUD_FOUNDRY
# 启用CloudFoundry管理端点(通常由上一条配置自动触发)
management.cloudfoundry.enabled=true
# 暴露所有Actuator端点
management.endpoints.web.exposure.include=*

4.3 安全配置(存在漏洞的配置)

创建一个安全配置类,意图是保护 /cloudfoundryapplication/** 路径,但由于自动配置的干扰,此配置不会生效

@Configuration
@EnableWebSecurity
public class SecurityConfig {
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/actuator/health").permitAll()
                .antMatchers("/cloudfoundryapplication/**").authenticated() // 此配置将被覆盖/忽略
                .anyRequest().authenticated()
            .and()
            .httpBasic()
            .and()
            .csrf().disable();
        return http.build();
    }
    // ... UserDetailsService 配置 ...
}

4.4 漏洞触发控制器

创建映射到漏洞路径的自定义控制器:

@RestController
@RequestMapping("/cloudfoundryapplication")
public class CloudFoundryAppController {
    @GetMapping("/admin")
    public String admin() {
        return "ADMIN_ENDPOINT_EXPOSED - This should require authentication!";
    }
    @GetMapping("/secrets")
    public String secrets() {
        return "SECRET_DATA: database_password=root123, api_key=sk-secret-key";
    }
}

4.5 启动验证

启动应用后,在日志中查找关键信息,确认漏洞条件成立:

WARN  o.s.s.c.a.web.builders.WebSecurity : You are asking Spring Security to ignore Ant [pattern='/cloudfoundryapplication/**']. This is not recommended
INFO  o.s.s.web.DefaultSecurityFilterChain : Will not secure Ant [pattern='/cloudfoundryapplication/**']

出现以上警告和信息日志,表明 CloudFoundry 自动配置已生效,并强制 Spring Security 忽略了对该路径的保护。

4.6 漏洞复现

直接访问自定义端点,无需提供任何认证凭证(如Basic Auth的用户名密码):

GET http://localhost:8080/cloudfoundryapplication/admin
GET http://localhost:8080/cloudfoundryapplication/secrets

预期结果(错误):应返回 200 OK 及控制器返回的敏感信息。
正确结果:应返回 401 Unauthorized。

作为对比,访问一个配置在非 /cloudfoundryapplication 路径下的受保护端点(如 /normal),则会正常要求认证。

5. 漏洞深度分析

5.1 自动配置类分析

spring-boot-actuator-autoconfigure-2.7.8.jar 中,CloudFoundryActuatorAutoConfiguration 包含一个内部类:

@Order(SecurityProperties.IGNORED_ORDER)
static class IgnoredCloudFoundryPathsWebSecurityCustomizer implements WebSecurityCustomizer {
    @Override
    public void customize(WebSecurity web) {
        // 漏洞核心:粗粒度地忽略了整个路径
        web.ignoring().requestMatchers(new AntPathRequestMatcher("/cloudfoundryapplication/**"));
    }
}

@Order(SecurityProperties.IGNORED_ORDER) 保证了该配置器以高优先级(低order值)执行,覆盖了开发者在 SecurityConfig 中的配置。

5.2 请求处理流程剖析

  1. 请求进入GET /cloudfoundryapplication/admin
  2. 安全过滤:由于 web.ignoring(),Spring Security 的所有 Filter 跳过此请求。
  3. Handler 解析
    a. DispatcherServlet 询问 CloudFoundryWebEndpointServletHandlerMapping 能否处理 “/admin”。
    b. 该 HandlerMapping 检查其注册表,发现 “/admin” 不是一个已注册的 CloudFoundry 端点,返回 null
    c. DispatcherServlet 继续询问 RequestMappingHandlerMapping
    d. RequestMappingHandlerMapping 成功匹配到 CloudFoundryAppController.admin() 方法,并返回对应的处理器。
  4. 执行业务逻辑:控制器方法执行,返回数据。
  5. 响应返回:HTTP 200 及敏感数据被返回给未认证的客户端。

6. 修复方案与演变

6.1 中间修复 (Spring Boot 2.7.9 - 2.7.18)

Spring 团队在 2.7.9 版本中改进了 IgnoredCloudFoundryPathsWebSecurityCustomizer 的逻辑:

@Override
public void customize(WebSecurity web) {
    List<RequestMatcher> requestMatchers = new ArrayList<>();
    // 关键变化:只忽略已注册的CloudFoundry端点路径,而非整个 `/cloudfoundryapplication/**`
    this.pathMappedEndpoints.getAllPaths()
            .forEach((path) -> requestMatchers.add(new AntPathRequestMatcher(path + "/**")));
    requestMatchers.add(new AntPathRequestMatcher(BASE_PATH)); // BASE_PATH = “/cloudfoundryapplication“
    requestMatchers.add(new AntPathRequestMatcher(BASE_PATH + "/"));
    web.ignoring().requestMatchers(new OrRequestMatcher(requestMatchers));
}

效果与局限:此修复缩小了 Spring Security 的忽略范围。然而,由于 CloudFoundryWebEndpointServletHandlerMapping 仍然没有处理未知路径的机制,自定义控制器的请求依然会 “fall through“ 并被处理,漏洞仍然存在,只是利用条件稍严格

6.2 完整修复 (Spring Boot 2.7.32+, 3.5.12+, 4.0.4+)

真正的修复是在 CloudFoundryWebEndpointServletHandlerMapping 层级增加了“兜底处理”(catch-all)机制。

  1. 在 HandlerMapping 初始化时注册兜底处理器

    @Override
    protected void initHandlerMethods() {
        super.initHandlerMethods();
        // 注册一个匹配 /** 的处理器,用于拦截所有未明确注册的路径
        registerCatchAllMapping(HttpStatus.FORBIDDEN);
    }
    
  2. 兜底处理器的实现

    protected void registerCatchAllMapping(HttpStatus responseStatus) {
        String subPath = this.endpointMapping.createSubPath("/**");
        registerMapping(
            RequestMappingInfo.paths(subPath).options(this.builderConfig).build(),
            new CatchAllHandler(responseStatus), // 返回指定状态码的处理器
            this.catchAllMethod
        );
    }
    private static final class CatchAllHandler {
        private final HttpStatus responseStatus;
        void handle(HttpServletResponse response) {
            response.setStatus(this.responseStatus.value()); // 例如返回 403
        }
    }
    

效果:现在,任何访问 /cloudfoundryapplication/** 下未在 CloudFoundry 注册的路径的请求,都会被 CatchAllHandler 拦截,并直接返回 403 Forbidden,而不会再传递给下游的 RequestMappingHandlerMapping。至此,认证绕过漏洞被彻底堵塞。

7. 修复与缓解建议

7.1 根本解决(推荐)

  • 升级Spring Boot:将应用升级到已修复的版本。
    • Spring Boot 2.7.x 用户升级至 2.7.32 或更高。
    • Spring Boot 3.3.x 用户升级至 3.3.18 或更高。
    • Spring Boot 3.4.x 用户升级至 3.4.14 或更高。
    • Spring Boot 3.5.x 用户升级至 3.5.12 或更高。
    • Spring Boot 4.0.x 用户升级至 4.0.4 或更高。

7.2 临时缓解措施

如果无法立即升级,可考虑以下方案:

  • 方案A:修改应用代码
    绝对不要将自定义的控制器端点映射到 /cloudfoundryapplication/ 路径下。为应用接口使用独立的、无冲突的上下文路径,例如 /api/**/app/**

  • 方案B:添加安全补丁
    在安全配置中,手动添加一个高优先级的过滤器(Filter)来拦截 /cloudfoundryapplication/* 路径下的未知请求。示例如下:

    @Bean
    public FilterRegistrationBean<CatchAllFilter> catchAllFilter() {
        FilterRegistrationBean<CatchAllFilter> registration = new FilterRegistrationBean<>();
        registration.setFilter(new CatchAllFilter());
        registration.addUrlPatterns("/cloudfoundryapplication/*");
        registration.setOrder(Ordered.HIGHEST_PRECEDENCE); // 设置为最高优先级
        return registration;
    }
    public static class CatchAllFilter implements Filter {
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
            HttpServletRequest req = (HttpServletRequest) request;
            String path = req.getRequestURI().substring(req.getContextPath().length());
            // 此处可添加逻辑,判断是否为CloudFoundry已知端点,否则拦截
            // 简单示例:对于非根路径的未知请求直接拒绝
            if (!path.equals("/cloudfoundryapplication") && !isKnownCloudFoundryPath(path)) {
                ((HttpServletResponse) response).setStatus(HttpServletResponse.SC_FORBIDDEN);
                return;
            }
            chain.doFilter(request, response);
        }
        private boolean isKnownCloudFoundryPath(String path) {
            // 实现逻辑,检查path是否在已知的CloudFoundry Actuator端点列表中
            return false;
        }
    }
    

8. 参考资料

  • GitHub Advisory: GHSA-mgvc-8q2h-5pgc
  • NVD: CVE-2026-22733
  • Spring Boot Issue #49645
  • 修复 Commit: 01fbede
相似文章
相似文章
 全屏