Spring Boot Actuator 暴露 heapdump,内存里的密码可能全漏了
线上开了 Actuator,本来是为了方便排查问题。
结果
/actuator/heapdump也暴露出去了。一份堆转储文件下载下来,数据库连接串、Redis 密码、Token、用户请求参数,都可能躺在里面。
一、事故现场
有个项目为了方便线上排查,开了 Spring Boot Actuator。
配置大概是这样:
management:endpoints:web:exposure:include:"*"开发同学当时的想法很简单:
先全部打开,线上排查方便一点。
结果某天安全扫描扫出来:
/actuator/env /actuator/metrics /actuator/heapdump /actuator/threaddump这些端点都能访问。
其中最危险的是:
/actuator/heapdump这个接口会导出 JVM 当前堆内存快照。
换句话说:
JVM 里活着的对象,它都可能出现在 heapdump 里。
这就不是“暴露一点监控信息”的问题了。
这是把应用内存打包交出去了。
二、heapdump 里到底有什么?
很多人低估了 heapdump 的敏感程度。
它不是普通日志。
它是 JVM 堆内存快照。
里面可能包含:
配置对象 数据库连接信息 Redis 连接信息 MQ 连接信息 第三方 API Token JWT / Session / Cookie 用户请求参数 接口返回数据 缓存对象 业务实体 异常堆栈 临时字符串比如项目里有这种配置:
spring:datasource:url:jdbc:mysql://10.0.0.12:3306/order_dbusername:order_userpassword:Abc123456redis:host:10.0.0.20password:redis-secret这些配置在应用启动后,通常会被绑定成 Java 对象。
只要对象还在堆里,就有可能出现在 heapdump 文件中。
再比如请求里带了 Token:
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9...或者用户刚提交过敏感参数:
{"mobile":"13800000000","idCard":"xxx","password":"xxx"}这些字符串如果还没被 GC,也可能在堆快照里被找到。
所以 heapdump 暴露的风险不是“看一下内存占用”。
而是:
把应用运行时的敏感数据一起暴露了。
三、为什么很多项目会误开?
最常见的是这行配置:
management:endpoints:web:exposure:include:"*"这表示暴露所有 Web 端点。
开发环境这么配,问题不大。
但如果生产也这么配,就危险了。
还有一种写法:
management:endpoints:web:exposure:include:health,info,metrics,env,heapdump,threaddump看起来比*收敛了一点。
但heapdump、env、threaddump仍然是高风险端点。
尤其是这些:
| 端点 | 风险 |
|---|---|
/actuator/heapdump | 导出 JVM 堆内存,可能包含密码、Token、用户数据 |
/actuator/env | 暴露环境变量、配置项和配置来源;旧版本或配置不当时可能泄露敏感值 |
/actuator/configprops | 暴露配置绑定对象;旧版本或配置不当时可能泄露敏感值 |
/actuator/threaddump | 暴露线程栈、类名、方法名、业务路径 |
/actuator/logfile | 暴露日志内容 |
/actuator/mappings | 暴露接口路由 |
这些东西对开发排查很方便。
对攻击者也很方便。
这里要补一个版本细节。
较新的 Spring Boot 对/actuator/env、/actuator/configprops这类端点默认会做敏感值脱敏,很多密码字段不会直接明文展示。
但这不代表它们就可以放心暴露。
因为它们仍然会暴露配置结构、属性名、配置来源、组件信息和内部实现细节。如果项目使用旧版本、改过脱敏规则,或者把show-values配成了always,敏感值仍然可能被打出来。
而/actuator/heapdump的风险更直接。
它导出的是堆内存快照,不是经过脱敏处理的配置视图。
四、Actuator 默认不是原罪,乱暴露才是
Actuator 本身不是问题。
它是非常好用的生产诊断工具。
问题在于:
暴露范围太大 没有鉴权 直接挂公网 生产和开发共用一套配置安全的做法不是“永远不用 Actuator”。
而是生产环境只开放必要端点。
比如最小配置:
management:endpoints:web:exposure:include:health,info如果接入 Prometheus:
management:endpoints:web:exposure:include:health,info,prometheus不要为了省事写:
include:"*"这行配置在生产环境里非常刺眼。
五、生产环境应该怎么配?
1. 只暴露必要端点
推荐:
management:endpoints:web:exposure:include:health,info,prometheus不推荐:
management:endpoints:web:exposure:include:"*"如果没有监控采集需求,甚至可以只留:
management:endpoints:web:exposure:include:health2. health 不要暴露过多细节
很多项目会开:
management:endpoint:health:show-details:always这会把很多健康检查细节暴露出去。
生产环境更建议:
management:endpoint:health:show-details:never或者只对已认证用户展示:
management:endpoint:health:show-details:when_authorized3. 管理端口和业务端口分开
可以把 Actuator 放到单独端口:
management:server:port:9090然后通过安全组、内网、防火墙限制访问。
比如:
业务端口 8080:对外开放 管理端口 9090:只允许内网监控系统访问这样即使业务接口暴露公网,管理端点也不会跟着裸奔。
4. 加鉴权
如果管理端点必须通过 HTTP 访问,至少要加鉴权。
比如只允许管理员角色访问:
@ConfigurationpublicclassActuatorSecurityConfig{@BeanSecurityFilterChainactuatorSecurityFilterChain(HttpSecurityhttp)throwsException{http.securityMatcher(EndpointRequest.toAnyEndpoint()).authorizeHttpRequests(auth->auth.requestMatchers(EndpointRequest.to("health","info")).permitAll().anyRequest().hasRole("ACTUATOR_ADMIN")).httpBasic(Customizer.withDefaults());returnhttp.build();}}具体写法会随 Spring Security 版本变化,但原则不变:
非公开端点必须鉴权。
5. 明确关闭高危端点
如果不需要 heapdump,可以显式关掉:
management:endpoint:heapdump:enabled:false也可以关闭其他高危端点:
management:endpoint:env:enabled:falseconfigprops:enabled:falsethreaddump:enabled:falselogfile:enabled:false注意:端点“启用”和“暴露”是两回事。
一个端点可能在应用内部启用了,但没有通过 Web 暴露。
在较新的 Spring Boot 版本里,还可以额外通过端点访问级别控制某个端点是不可访问、只读,还是允许完整访问。不同版本的配置项名字会有差异,落地时要按自己项目的 Spring Boot 版本确认。
生产环境要同时关注:
enabled exposure access network access authentication如果确实需要临时开放env或configprops给内网排查,至少不要在生产环境使用:
management:endpoint:env:show-values:alwaysconfigprops:show-values:always更稳的做法是保持敏感值不展示,或者只对已认证、已授权的用户展示。
六、已经暴露过 heapdump,怎么办?
如果你发现生产环境曾经暴露过/actuator/heapdump,不要只把配置改掉就结束。
建议按事故处理。
1. 立即下线暴露端点
先改配置:
management:endpoints:web:exposure:include:health,info,prometheusendpoint:heapdump:enabled:false同时确认网关、Nginx、安全组没有继续放行。
2. 检查访问日志
查这些路径有没有被访问过:
/actuator /actuator/heapdump /actuator/env /actuator/configprops /actuator/threaddump /actuator/logfile重点看:
访问 IP 访问时间 响应状态码 响应大小 是否有异常下载流量如果/actuator/heapdump返回过大文件,就要高度警惕。
3. 轮换密钥和密码
heapdump 里可能出现这些敏感信息:
数据库密码 Redis 密码 MQ 密码 对象存储密钥 第三方 API Token JWT 签名密钥 内部服务调用凭证如果确认有外部访问,建议轮换相关凭证。
不要赌“没人会分析那个文件”。
4. 检查异常登录和异常调用
如果数据库、Redis、对象存储、第三方平台有审计日志,要一起看。
重点看:
陌生 IP 登录 异常时间段访问 大量读取 失败重试 权限变更 新增账号Actuator 泄露本身只是入口。
真正的损失可能发生在后面。
七、团队规范:生产 Actuator 最小化
如果让我给团队定一条规范,我会这样写:
生产环境禁止 exposure.include=* 生产环境默认只开放 health、info、prometheus heapdump、threaddump、logfile 不允许公网访问 env、configprops 不允许公网访问,确需内网开放时也不要展示敏感值 管理端口必须走内网或鉴权 所有 Actuator 配置必须区分 dev/test/prod配置可以分环境。
开发环境:
# application-dev.ymlmanagement:endpoints:web:exposure:include:"*"endpoint:health:show-details:always生产环境:
# application-prod.ymlmanagement:endpoints:web:exposure:include:health,info,prometheusendpoint:health:show-details:neverheapdump:enabled:falseenv:enabled:falseconfigprops:enabled:falsethreaddump:enabled:falselogfile:enabled:false这才是比较稳的方式。
不要让开发配置跟着一起上生产。
八、上线前 checklist
上线前看到 Actuator,建议过一遍这个表。
| 检查项 | 风险 | 建议 |
|---|---|---|
是否配置include: "*" | 所有端点暴露 | 生产禁止 |
是否暴露heapdump | 堆内存泄露 | 关闭或仅内网鉴权 |
是否暴露env | 配置结构、环境变量和敏感值泄露风险 | 关闭;确需开放时鉴权并避免show-values: always |
是否暴露configprops | 配置对象和敏感值泄露风险 | 关闭;确需开放时鉴权并避免show-values: always |
是否暴露logfile | 日志敏感信息泄露 | 关闭 |
| 管理端口是否公网可访问 | 被扫描命中 | 内网隔离 |
| health 是否展示详情 | 泄露组件信息 | prod 用never |
| dev/prod 配置是否隔离 | 开发配置上生产 | 分环境配置 |
| 是否有访问日志 | 暴露后难追踪 | 网关/Nginx 留日志 |
九、总结
Actuator 是好工具。
但生产环境里,它不是给所有人看的。
尤其是/actuator/heapdump。
它导出的不是普通监控数据,而是 JVM 堆内存快照。
里面可能有:
密码 Token 连接串 用户数据 业务对象 请求参数所以生产环境记住三句话:
不要
include: "*"。不要把管理端点挂公网。
不要无鉴权暴露 heapdump、env、configprops、logfile 这类高危端点。
下一篇准备写:@Async 默认执行器又炸了:SimpleAsyncTaskExecutor 为什么不是线程池。
如果你也在排查 Java 后端线上问题,可以关注公众号:云技纵横。
这个系列会持续更新 Spring 事务、线程池、JVM、MySQL、Redis、MQ 的真实踩坑复现。