尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

Spring Boot Actuator未授权访问:高频暴露面排查与安全加固

发布时间:2026/9/29 7:35:18

资讯中心
01
ARTICLE

Spring Boot Actuator未授权访问:高频暴露面排查与安全加固

Spring Boot Actuator未授权访问:高频暴露面排查与安全加固
前阵子一个做企业内部系统的朋友来找我说他们刚上线两周的运营后台被甲方安全扫描打了一堆高危报告里排第一的就是Spring Boot Actuator 未授权访问附件还贴了/actuator/env、/actuator/heapdump的直接响应截图连状态码 200 都标出来了。他当时的表情挺懵的——代码是自己写的鉴权框架也接了怎么就成了高危。我打开他们的application.yml看了三分钟就找到原因了management.endpoints.web.exposure.include: *一行为了调试方便留下的配置把整套运维端点直接摆到了公网入口。这件事让我觉得有必要把 Spring Boot 这类未授权访问问题系统讲一遍因为它的坑不在框架本身而在于默认约定、开发习惯和部署姿态这三件事叠在一起。这篇内容我想聊的就是Spring Boot 项目里常见的未授权访问面到底有哪些、它们为什么会出现、怎么自己查出来、以及怎么用配置和代码把它收干净。不管你是刚接触 Spring Boot 的开发者还是负责安全加固和应急的运维同学都能从里面找到能直接抄的配置和排查思路。1. 这个漏洞到底漏在哪Spring Boot 的默认约定与暴露面的由来1.1 一个真实场景上线第二天就被扫出来回到我那位朋友的案例。他们的技术栈是 Spring Boot 2.7 加 Spring Security接口层做了 JWT 校验这部分没问题。问题出在两个地方一是pom.xml里引入了spring-boot-starter-actuator却没有做任何暴露限制二是配置文件里为了本地调试方便开了management.endpoints.web.exposure.include: *并且没设置独立的管理端口。部署到云主机后Actuator 的端点跟着业务端口一起对外了。扫描器其实不会写什么高级规则它只是拿一份常见路径字典去撞。/actuator、/actuator/env、/actuator/health、/actuator/beans、/actuator/heapdump这些路径挨个请求一遍谁返回 200 并且响应体里有特征字符串就记一条。他们那次之所以被标成高危是因为/actuator/heapdump返回了一个几十兆的二进制文件——内存快照里可能包含运行时的配置属性、连接串、令牌片段。这就是未授权访问最典型的样子接口本身没漏洞但入口没锁等于把内部资料室的钥匙挂在了大门上。1.2 便利性与安全性的账Spring Boot 帮你怎么算的Spring Boot 的设计哲学是约定优于配置这句话在提升开发效率上非常成功但它在安全上有个隐含前提默认假设你部署在受信任的内网环境。Actuator 就是一个典型例子。它在 1.x 时代默认把所有端点都通过 HTTP 暴露出去因为那时候它的定位是内网运维工具。到了 2.x官方把默认暴露范围收窄到只剩health和info但保留了include: *这个开关也保留了对/env、/heapdump这类敏感端点的支持。这个设计的逻辑是把选择权交给开发者。问题是很多开发者根本不知道有这道选择题。项目脚手架生成什么样就用什么样教程里写include: *就跟着抄本地跑通就行没人会去想上线之后这些路径会变成什么样。所以我一直跟团队里的人说Spring Boot 的安全问题八成不是写错了而是没想过。你要做的第一件事是把项目里所有跟暴露端口监控控制台相关的配置项列出来逐个问自己一句这东西上线以后谁能访问到从影响范围看这类问题的波及面比想象中大。它不是某一个业务接口的问题而是一整类旁路入口的问题。业务接口的鉴权你可能做得很扎实但旁路入口走的是另一套逻辑它们往往不经过你的 JWT 过滤器也不在你的接口权限表里。一旦被扫到轻则泄露接口清单、配置项、依赖版本重则泄露内存中的敏感数据。而扫描这类问题是全自动的、批量的、成本极低的这就意味着你只要暴露了被发现的概率几乎是 100%。2. 六大高频暴露面盘点按危害等级排个序2.1 Actuator最典型的运维后门变前台入口Actuator 是 Spring Boot 官方提供的生产级监控模块端点数量很多我按敏感程度分三档说。第一档是信息泄露类包括/env环境变量与配置属性、/configprops配置 Bean 的属性、/beans容器里所有 Bean 定义、/mappings全部请求路由映射、/heapdump堆内存快照、/threaddump线程栈、/logfile日志文件。这里面/mappings的价值在于它能直接把你的全部接口路径吐出来包括那些没写进文档的内部接口/heapdump更狠它是一个二进制文件里面可能有数据库连接串、第三方密钥、用户会话对象。第二档是可操作类/loggers能动态修改日志级别/shutdown能直接关闭应用2.x 默认不通过 Web 暴露但可以手动开/jolokia是 JMX over HTTP 的桥能读甚至能操作 MBean这条链在历史上有过被用来做远程代码执行的记录。第三档是弱信息类/health、/info、/metrics、/caches单独看危害不大但/metrics会暴露内部指标名/health的show-details打开后会暴露数据库、磁盘、中间件的健康状态和版本信息这些都能作为下一步探测的情报。要注意的一个细节是/env在 2.0 之后对形如password、secret、key的属性名做了脱敏显示成******。但这不代表安全因为脱敏只是展示层的处理/heapdump拿到的是内存原始数据脱敏在这里完全无效。所以我看了/env都是星号应该没事这个判断是错的。2.2 API 文档页Swagger 与 Knife4j 把接口清单白送Swagger 是接口文档的事实标准springfox和springdoc-openapi两个生态都在用。问题在于这些文档页默认是不需要认证的因为它们是给开发者看的。常见的暴露路径包括/swagger-ui.html、/swagger-ui/index.html、/v2/api-docs、/v3/api-docs、/v3/api-docs/swagger-config如果用 Knife4j 的话还有/doc.html和/v2/api-docs?groupxxx这种分组的接口。这些页面的危害不在于能调用接口而在于它把接口的完整结构、参数名、参数类型、示例值、甚至注解里写的注释全部暴露出来。攻击者拿到这份清单等于拿到了你的系统地图接下来所有的接口探测都不用猜了。我在做应急的时候见过一个案例某系统的/v3/api-docs没关里面有个内部接口叫/internal/user/exportAll参数只有page和size返回全量用户数据。这个接口在业务侧是有权限控制的但接口名和参数结构被文档页泄露后攻击者直接把请求打过去发现开发环境的一个配置疏忽让这个接口的鉴权被跳过了。文档页的另一个麻烦是它常常被随手开着忘记关。很多团队在上线前会关掉但灰度环境、预发环境、内部测试域名上还留着而这些环境的域名有时候和主域名只差一个前缀很容易被枚举到。2.3 数据源监控台Druid 与 H2 Console如果项目里用了阿里 Druid 连接池并且引入了druid-spring-boot-starter会自带一个监控页面路径通常是/druid/index.html、/druid/sql.html、/druid/websession.html。这个页面的默认状态在早期版本里是不需要登录的后来加了login-username和login-password配置但很多项目要么没配要么配了默认的弱口令。Druid 监控页能干什么它能看实时 SQL 执行记录、慢 SQL、URI 监控、Session 监控。也就是说你系统在跑什么 SQL、哪个接口在调用、Session 里存了什么全都看得到。这个信息量比一般的接口泄露大得多因为它直接指向了数据层。SQL 监控页里往往能看到完整的表名和字段名配合/actuator/mappings拿到的接口清单攻击者可以对你的数据模型做相当精确的推断。H2 Console 是另一个高频问题。H2 是内存数据库很多人拿它做单元测试和本地开发配置项是spring.h2.console.enabledtrue路径是/h2-console。这个开关如果被带到了生产配置里并且spring.h2.console.settings.web-allow-others被设成了true就会允许远程连接数据库控制台。虽然生产环境一般不会用 H2 存业务数据但这个控制台存在本身就是一个信息泄露点而且它经常和开发配置被误提交这类问题捆绑出现。2.4 集成中间件的连带风险Redis、MongoDB、Nacos这一块严格说不算 Spring Boot 框架本身的漏洞但它在Spring Boot 项目被扫出未授权访问的场景里出现的频率非常高因为 Spring Boot 集成这些中间件太方便了。Redis 在 Spring Boot 里通过spring-boot-starter-data-redis集成配置项是spring.redis.host和spring.redis.port。如果这台 Redis 部署时没设密码并且监听在0.0.0.0那么它就是未授权可访问的。同样的问题在 MongoDB 上更常见早年 MongoDB 默认不开认证spring.data.mongodb.uri里如果没有用户名密码连接的就是无认证实例。Nacos 的情况类似作为注册中心和配置中心它的 Namespace 权限模型在旧版本里比较粗糙默认的nacos/nacos账号如果没改配置列表和注册实例列表就能被直接读到。这反过来会泄露什么你所有微服务的配置都可能在 Nacos 里包括数据库密码、消息队列地址、第三方密钥。注意这类问题的判断标准很简单——只要中间件端口能从你的业务网段之外访问到且没有认证就应该按未授权访问处理不要因为它是内部组件就降低优先级。2.5 配置泄露的放大效应一处的口子可能撬开全局我特别想强调这一点因为它经常被低估。单独看/actuator/env泄露或者heapdump下载好像只是泄露了一些配置。但如果你的系统里 JWT 的签名密钥是写在配置文件里的那么这条链就变成了/actuator/env泄露jwt.secret攻击者用这个密钥自己签发一个管理员角色的 Token业务侧接口的 JWT 校验形同虚设。这时候漏洞的性质就从信息泄露升级成了认证绕过。同样的逻辑也适用于 Druid 连接池密码、内部服务间调用的签名盐值、加密用的初始化向量。这些值本身不直接暴露数据但它们是信任链的根。所以我做安全评审的时候有个习惯先找哪些配置项是密钥类的再检查这些配置项可能通过哪些路径泄露出去。这个思路比逐个检查端点有效得多因为它是按资产价值而不是按暴露面数量来排优先级的。3. 自查怎么查源码、运行时、外部视角三层联动3.1 源码层先搜配置关键词五分钟摸清底牌第一层永远是看代码和配置因为这是你完全可控的部分。我会在项目根目录跑一组关键词搜索重点找这几类内容management.endpoints、exposure、swagger、springdoc、knife4j、druid、h2.console、spring.redis、spring.data.mongodb、eureka.client、nacos。看的时候关注三件事开关有没有开、路径有没有改、有没有独立端口。举个具体的判断例子application.yml里如果出现下面这段基本可以确认存在问题management: endpoints: web: exposure: include: * endpoint: health: show-details: alwaysinclude: *是全量暴露show-details: always会把健康检查的细节暴露出来包括数据库连接状态和磁盘路径。这两条单独看都不算致命组合在一起就是一个完整的信息收集入口。搜索的时候还要注意多环境配置文件的覆盖关系。application-dev.yml、application-test.yml、application-prod.yml的加载顺序和spring.profiles.active直接相关经常出现的情况是 prod 配置写得很干净但application.yml顶层的某个开关没被覆盖掉结果线上还是开着的。我建议把每个 profile 的生效配置项用/actuator/configprops在测试环境导出一份对照看虽然这个做法听起来有点绕但它能发现很多以为关掉了其实没关的问题。3.2 运行时层从入口逐个验证端点真实状态源码确认之后要在运行时验证一遍因为配置写的和实际生效的可能不一致。做法是从业务入口地址出发逐个请求管理类路径看状态码和响应内容。判断标准我整理成了一张表方便直接对照路径正常状态风险状态风险说明/actuator404 或 401200 返回端点列表暴露全部可用端点名/actuator/env404 或 401200 返回属性列表配置项泄露脱敏不彻底/actuator/heapdump404 或 401200 返回大体积二进制内存数据泄露含明文密钥/actuator/mappings404 或 401200 返回全部路由内部接口清单泄露/swagger-ui/index.html404 或 401200 返回文档页接口结构完整泄露/v3/api-docs404 或 401200 返回 JSON接口定义可被程序化解析/druid/index.html404 或 401200 返回登录页或监控页SQL 与会话监控泄露验证的时候有个小技巧不要只看状态码要看响应体特征。有些项目做了全局异常处理所有 404 都返回一个 JSON 错误体这时候状态码是 200 但内容不对。反过来有些项目把管理端点挡在了统一鉴权后面返回 401 或 403这就是正常状态。另外注意 gzip 压缩的情况heapdump这类端点在压缩后响应体很小不能靠响应大小来判断要看Content-Type是不是application/octet-stream这类二进制类型。3.3 外部视角把资产测绘当成定期体检第三层是站在外部视角看。这一步不是为了攻击自己而是为了知道如果我是扫描器我会看到什么。做法是把你的域名、IP 段、常见子域名整理成资产清单用合规的资产梳理工具或者自查脚本从公网侧发起请求记录哪些管理路径是可访问的。这里我要提醒一点做这一步一定要走内部审批只对自己拥有或明确授权的资产做不要扫到别人的 IP 段去。技术上资产测绘的重点是三个维度——域名解析范围、端口开放情况、路径可访问性。很多团队的暴露面问题其实不在应用层而在于一个测试环境的域名解析到了公网 IP上面跑着和主站一样的代码管理端点全开。我自己的习惯是每个月做一次这样的梳理把结果和上个月的做对比新增的可访问路径就是新增的风险。这样做的好处是能发现配置漂移——上线时关掉的开关某次版本发布后又被带回来了。这种问题靠人眼盯配置是盯不住的只能靠定期扫描出来的结果说话。4. 加固实操配置、代码、网关三道闸门4.1 第一道闸Actuator 最小化暴露最有效的加固是最小化。如果你的项目不需要 Actuator 的运维能力最直接的做法是把它从依赖里去掉。很多项目引入它只是为了用/health做健康检查而健康检查完全可以用一个自己写的简单接口替代。这一刀砍下去整个暴露面直接消失。如果确实需要保留 Actuator那就从配置上收紧。我推荐的做法有三条只暴露必要端点、把管理端点放到独立端口、把管理端口限制在内网地址。management: server: port: 9090 address: 127.0.0.1 endpoints: web: base-path: /_ops exposure: include: health,info,prometheus exclude: env,heapdump,threaddump,mappings,beans,configprops endpoint: health: show-details: never这几行配置里每一行都有明确的意图。server.port把管理端点从业务端口上剥离出来address: 127.0.0.1让它只在回环地址上监听这样即使有人扫到 9090也只能从本机访问。base-path改成一个非默认值能让基于默认路径字典的自动化扫描失效但不要把它当成安全措施它只是提高门槛。include用白名单列出真正需要的端点exclude作为双保险再排除一遍敏感项。show-details: never关掉健康检查的细节输出避免暴露依赖组件的状态。注意base-path修改后要同步更新你的监控系统和探针配置否则健康检查会全部失败导致误报警。这个改动建议先在测试环境跑一轮完整的发布流程再上生产。4.2 第二道闸给管理端点加上认证如果管理端点确实需要跨机器访问那第二道闸就是认证。Spring Boot 和 Spring Security 的配合很自然可以用EndpointRequest把管理端点和业务请求分开处理。Configuration public class ActuatorSecurityConfig { Bean public SecurityFilterChain actuatorChain(HttpSecurity http) throws Exception { http.securityMatcher(EndpointRequest.toAnyEndpoint()) .authorizeHttpRequests(auth - auth .requestMatchers(EndpointRequest.to(health, info)).permitAll() .anyRequest().hasRole(OPS)) .httpBasic(Customizer.withDefaults()) .csrf(csrf - csrf.disable()); return http.build(); } }这段代码的思路是健康检查这类探针路径允许匿名访问其余所有管理端点都需要OPS角色。securityMatcher是关键它让这条过滤链只作用于管理端点不会影响你的业务接口鉴权逻辑。生产环境里建议把httpBasic换成基于内部证书或统一身份体系的认证方式基础认证在跨网络传输时还是需要 TLS 保护的。有一点必须说清楚这道闸门的前提是业务侧的鉴权链路本身是可靠的。如果你的 JWT 校验存在密钥泄露或者算法混淆之类的问题那么管理端点的认证也可能被一并绕过。所以加固顺序是先把认证链路的根问题解决掉再给管理端点加认证否则就是在沙子上盖楼。4.3 第三道闸网关统一收口与路径治理前两道闸是应用层的第三道闸放在网关层。不管你的架构是 Nginx 反向代理还是 Spring Cloud Gateway都可以在入口处对管理类路径做统一拦截。这层的好处是维护成本低新增服务不用每个都改配置。Nginx 的写法比较直接location ~* ^/(actuator|swagger-ui|v2/api-docs|v3/api-docs|doc.html|druid|h2-console) { deny all; return 403; }这段配置把常见的敏感路径全部拒绝。要注意~*是大小写不敏感匹配因为有些框架的路径大小写处理不一致用不敏感匹配更保险。如果某些路径确实需要对外提供比如健康检查给负载均衡用就把它从正则里摘出来单独放行并且限制来源 IP。Spring Cloud Gateway 的做法类似用Path断言配合一个高优先级的过滤器在请求进入业务路由之前返回 403。这里有个细节值得注意过滤器的执行顺序要用order明确指定让它排在鉴权和路由转发之前否则可能出现请求已经被转发到后端才被拦截的情况那样既浪费资源也可能在后端日志里留下痕迹。5. 踩坑实录与常见问题排查5.1 常见问题速查表实际排查中遇到的问题大多集中在下面这几类我整理成了对照表现象可能原因排查方向配置里关了端点但线上仍可访问多 profile 配置未覆盖或配置中心下发了旧配置对比/actuator/configprops实际生效值检查配置中心命名空间返回 401 但仍被判定为高危扫描器把 401 视为端点存在结合响应体判断必要时把路径直接改为 404修改 base-path 后探针全部失败监控系统未同步更新路径先更新探针配置再发布应用heapdump响应很小响应被 gzip 压缩检查Content-Type与Content-Encoding头关掉 Actuator 后 Swagger 还在两套配置相互独立分别处理 Actuator 与文档组件不要混为一谈内网环境能访问但公网不能管理端口监听地址受限确认management.server.address配置生效版本升级后端点路径变了2.x 与 1.x 的默认前缀和暴露策略不同按实际版本核对官方配置项名称5.2 几个只有踩过才知道的细节第一个细节是关于回滚的。有些团队在加固时把管理端点的路径和端口全改了一遍结果监控告警配置没跟着改发布之后监控瞎了整整一个晚上第二天才发现。我的建议是加固方案分两次发布第一次先把暴露范围收窄到白名单路径和端口不动观察一周第二次再改路径和端口并且提前和监控团队对齐。第二个细节是关于依赖传递的。你可能没在pom.xml里直接写 Actuator但某个内部基础组件把它作为依赖带进来了这种情况很难靠读自己的配置文件发现。排查方法是跑一次mvn dependency:tree或者gradle dependencies在输出里搜actuator和swagger看到意外出现的依赖就顺着往上查是谁引入的。第三个细节是关于版本判断的。很多扫描报告的标题会写Spring Boot Actuator 未授权访问但实际的风险等级取决于你暴露了哪些端点。如果只暴露了health那基本没有实际危害如果暴露了heapdump或jolokia那就要按高危处理。收到报告后第一件事是确认实际可访问的端点列表而不是看到标题就慌。判断顺序是先看有没有二进制下载类端点再看有没有 MBean 操作类端点最后看信息类端点按这个优先级确定修复顺序。第四个细节是在排查过程中保存证据。做加固之前把当前的端点响应状态、配置文件内容、依赖树输出都存一份归档加固之后再采一次形成前后对比。这有两个好处一是能量化说明加固效果二是在出现改了之后业务异常的情况时能快速定位是哪一项配置引起的。我自己维护过一份简单的检查清单每次发布前过一遍虽然有点笨但它确实帮我拦下过好几次配置回潮的问题。最后分享一个我在实际项目里固定的习惯把管理类路径的访问全部接入访问日志并且对来自非内网网段的请求单独打标告警。即便某次配置疏忽让端点短暂暴露了也能通过日志知道有没有人真的访问过、访问了哪些路径。这比事后去猜到底有没有被利用要靠谱得多也是我觉得投入产出比最高的一项防护措施。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。