如果服务运行 Spring Boot 4.0.0–4.0.5,先把 Spring Boot 4.0.6 纳入最高优先级升级清单,再逐项核对 Actuator 授权、Remote DevTools 可达性、RabbitMQ 主机名校验、${random.value} 的用途、ApplicationTemp 目录所有权和 PID 文件路径。版本命中只是第一步,暴露面、配置条件和攻击者位置共同决定风险能否被触发。
仅做“升级一个框架版本”不足以覆盖 Java 生态的安全升级。JDK 运行时、Spring Boot 及传递依赖、Undertow 等服务器组件、业务代码分别拥有独立的补丁线;只更新 Spring Boot,既不能替代 Java 25 安全补丁,也不能消除 XXE、JNDI、反序列化或表达式注入等代码入口。 近期掘金热榜文章《继PHP之后,Java也爆出了重大安全漏洞!》可作为启动排查的线索。现有补充资料没有提供足够细节支撑具体漏洞结论,因此本文只采用资料中明确给出的版本、触发条件和修复信息,缺失字段统一标记为待官方公告确认。
先分清风险所在层级
排查时先建立一张分层清单,避免把“发现组件版本”与“确认可利用”混为一谈。
| 层级 | 典型对象 | 主要风险 | 修复责任 |
|---|---|---|---|
| JDK 运行时 | Java 25 及对应安全补丁构建 | 运行时漏洞、补丁缺失 | 平台与基础设施团队 |
| 框架与依赖 | Spring Boot、Spring Framework、RabbitMQ 客户端、Elasticsearch 组件等 | 未授权访问、证书校验缺陷、弱随机数等 | 应用与依赖治理团队 |
| Web 服务器组件 | Undertow 等嵌入式服务器 | Host 头注入等请求处理缺陷 | 框架或基础设施团队 |
| 业务代码 | XML 解析、JNDI 查找、反序列化、表达式求值 | 外部实体读取、远程类加载、危险对象实例化等 | 业务研发团队 |
Java 25 的公开资料只概括了安全补丁和兼容性要求,其中一份资料提到 9 个高危漏洞,但没有逐项给出 CVE 编号、受影响构建和修复构建,因此不能用“已经升级到 Java 25”替代“已经安装包含对应修复的 Java 25 安全补丁”。
盘点实际版本和暴露面
版本盘点应以运行时和最终解析出的依赖为准,而不是只看 pom.xml、Gradle 文件或镜像标签。容器、虚拟机和 CI 环境可能使用不同的 JDK,同一应用也可能通过 BOM、传递依赖或 shaded JAR 引入不同版本的组件。
先记录实际运行的 Java:
java -version
java -XshowSettings:properties -version
核对 java.home、java.runtime.version 和镜像中的运行时路径,再查看 Spring Boot、RabbitMQ、Elasticsearch、Undertow 等组件的解析结果:
./mvnw -q dependency:tree -Dverbose
./gradlew dependencies
./gradlew dependencyInsight --dependency spring-boot --configuration runtimeClasspath
生产项目应使用组织已经批准的 SBOM 工具生成清单,不要为了生成一次 SBOM 临时引入未经评估的新插件。SBOM 需要和镜像摘要、依赖树及部署清单相互对应,否则只能说明“曾经解析过哪些依赖”,不能证明当前运行制品的实际内容。
盘点表至少包含以下字段:
| 组件 | 实际版本 | 来源 | 暴露面 | 负责人 | 补丁窗口 |
|---|---|---|---|---|---|
| Spring Boot | 4.0.x | 依赖树、启动日志 | HTTP、管理端口 | 应用负责人 | 待填写 |
| Remote DevTools | 端口及依赖状态 | 监听端口、容器配置 | 内网或公网 | 平台负责人 | 待填写 |
| RabbitMQ | 客户端版本 | 依赖树 | TLS 连接 | 集成负责人 | 待填写 |
| Undertow | 实际解析版本 | 依赖树、镜像 | HTTP/HTTPS | 框架负责人 | 待填写 |
| JDK | 完整版本构建 | java -version |
全部 JVM 进程 | 基础设施负责人 | 待填写 |
同时登记管理端点访问规则、Remote DevTools 监听地址、RabbitMQ TLS 配置、临时目录和 PID 文件路径、随机数用途。登记后按实际状态确定处置节奏:
| 状态 | 判断依据 | 处置方式 |
|---|---|---|
| 已经暴露 | 脆弱端点可达、配置命中且缺少认证或隔离 | 立即关闭入口并纳入最高优先级升级 |
| 理论影响但尚未暴露 | 组件存在,但端口不可达、功能未启用或数据流不满足条件 | 仍需补丁,同时保留配置验证证据 |
| 暂时无法升级 | 停机窗口、兼容性或发布流程受限 | 执行临时止血,明确负责人和失效日期 |
| 已出现利用迹象 | 出现异常管理操作、连接、证书错误或文件异常 | 转入事件响应,不再按普通升级处理 |
| 升级后存在兼容性回归 | 新版本启动失败或业务行为变化 | 修复兼容性并重新验收,不能直接关闭工单 |
逐项核对 Spring Boot 触发条件
资料称 Spring Boot 4.0.6 一次修复了 8 个高危及中危漏洞,涉及 Actuator、DevTools、Elasticsearch 等组件。八项风险中,前五项具有资料给出的完整触发条件;PID 文件一项只有漏洞名称,Elasticsearch 和其他条目的具体 CVE、版本范围与修复参数仍需从官方公告补齐,不能根据二手文章推测。
| 风险项 | 受影响版本或版本信息 | 触发条件 | 可能后果 | 正式修复 | 临时措施 | 验收标准 |
|---|---|---|---|---|---|---|
| Actuator 未授权访问,CVE-2026-40976 | 明确为 Spring Boot 4.0.0–4.0.5 | 引入 Actuator,但安全规则缺失或配置不正确,且管理端点可被未认证用户访问 | 泄露监控数据、配置、环境变量,甚至执行关闭应用等管理操作 | 升级至 4.0.6,启用默认安全配置并拒绝未授权访问 | 添加 spring-boot-starter-security,只暴露必要端点,并为端点配置明确权限 |
匿名请求不能读取敏感端点或执行管理操作;授权用户仍可正常使用 |
| Remote DevTools 时序攻击,CVE-2026-40972 | 资料未单列精确范围;本次 4.0.x 升级线应优先覆盖 | Remote DevTools 可达,密钥验证采用非安全比较方式,攻击者能够进行高精度时间差分析 | 逐步推断验证密钥,连接 DevTools 后读取敏感信息或执行代码 | 4.0.6 改用常量时间比较;生产环境禁用 DevTools | 禁用远程 DevTools,阻断对应端口,并从生产制品中移除相关依赖 | 生产环境不监听 DevTools,未授权连接无法进入 |
| RabbitMQ SSL 主机名验证绕过,CVE-2026-40974 | 资料未单列精确范围;本次 4.0.x 升级线应优先覆盖 | 使用 RabbitMQ SSL 自动配置,主机名验证逻辑不一致;攻击者还能够伪造证书并处于中间人位置 | 应用与 RabbitMQ 之间的敏感数据被窃取 | 4.0.6 统一 SSL 主机名验证逻辑,默认执行严格校验 | 显式设置 spring.rabbitmq.ssl.verify-hostname=true |
错误主机名连接失败,正确主机名和有效证书连接成功 |
${random.value} 弱随机数,CVE-2026-40975 |
资料未单列精确范围;本次 4.0.x 升级线应优先覆盖 | ${random.value} 或同类 ${random.*} 被用于密钥、令牌等敏感凭据 |
随机序列可预测,敏感凭据可能被推断 | 4.0.6 默认改用 SecureRandom |
停止用 ${random.*} 生成敏感值,并轮换已经生成的凭据 |
代码和配置中不存在敏感用途,轮换记录完整 |
| ApplicationTemp 目录所有权问题,CVE-2026-40973 | 资料未单列精确范围;本次 4.0.x 升级线应优先覆盖 | 临时目录创建时未验证所有权,且攻击者能够劫持该目录 | 伪造会话文件、植入恶意代码,进一步造成会话劫持甚至远程代码执行 | 4.0.6 强化临时目录权限与所有权检查 | 按业务需要设置 server.servlet.session.persistent=false,并限制临时目录写权限 |
目录属于运行账户,其他用户不可写,符号链接或劫持目录不能生效 |
| PID 文件符号链接攻击 | 现有资料仅给出漏洞名称,CVE、精确版本和完整机制待官方公告 | PID 文件路径可被低权限用户预置、替换或通过符号链接劫持 | 完整后果需以官方公告为准,不能根据漏洞名称扩写 | 以 4.0.6 为框架升级目标,具体修复映射和参数仍需核对官方公告 | 检查 PID 路径所在目录所有权和写权限,拒绝异常链接或已存在文件 | 低权限用户不能预置或替换 PID 文件,应用不会跟随异常符号链接 |
| Elasticsearch 相关条目 | 资料仅说明本次更新涉及 Elasticsearch,未披露逐项参数 | 具体触发条件待官方公告 | 具体影响范围待官方公告 | 4.0.6 是资料给出的统一升级目标,精确 CVE 映射待补齐 | 在条目补齐前先核对 Elasticsearch 组件版本、端口和访问控制 | 按官方条目逐项通过验收 |
| 其他未披露条目 | 资料未给出对应名称和参数 | 待官方公告 | 待官方公告 | 4.0.6 是资料给出的统一升级目标,但不能据此替代精确版本判断 | 根据实际暴露面先做访问隔离 | 补齐 CVE、版本、触发条件和修复参数后重新验收 |
不能把“现有五个完整案例就是全部八项漏洞”当作完整结论。资料只完整展开了五项,PID 文件条目被截断,Elasticsearch 及其他条目也没有披露完整字段。 对外发布完整八项漏洞清单前,应以 Spring 官方公告逐项补齐 CVE、受影响版本、首个修复版本和配置说明。
版本扫描也不能替代暴露面验证。Actuator 风险取决于管理端点是否可达以及授权规则是否命中;DevTools 风险要求远程服务能够被连接;RabbitMQ 主机名验证绕过还需要攻击者具备伪造证书和实施中间人攻击的位置;弱随机数只有用于敏感凭据时才形成实质风险;临时目录问题则依赖攻击者是否拥有目录劫持条件。
发现利用迹象时先隔离
如果日志出现未授权 Actuator 管理操作、异常 DevTools 连接、RabbitMQ 证书异常、伪造会话文件或 PID 文件异常,应先按安全事件处理,而不是直接重启后继续运行。
第一,关闭相关入口。禁用 Remote DevTools,收紧 Actuator 管理端口和端点权限,暂停存在证书异常或行为异常的 RabbitMQ 连接,并限制临时目录及 PID 路径的写权限。
第二,保留证据。保存应用日志、网关日志、容器或主机进程信息、当前镜像摘要、配置快照、连接记录和异常文件。不要只保留一份经过重启后的日志,因为进程重启可能覆盖尚未持久化的关键上下文。
第三,轮换可能泄露的凭据。重点检查 Actuator 环境变量、配置文件和日志中出现过的密码、令牌、证书私钥,以及由弱随机数生成并投入使用过的凭据。只修改应用配置而不轮换已经暴露的值,不能消除既有风险。
第四,从可信环境重建。若已经出现文件植入、会话伪造或未知代码执行迹象,应使用可信基础镜像、经过扫描的依赖和重新生成的配置构建新制品,而不是在疑似失陷的实例上直接覆盖 JAR 后继续提供服务。
第五,完成隔离后再打补丁。保留旧制品、日志和镜像用于分析,同时让新制品通过完整回归,避免修复版本重新引入配置或供应链问题。
先止血再完成正式升级
无法立即停机时,临时措施的目标是缩小攻击面,而不是替代正式修复。可按实际场景采用以下配置:
spring.devtools.remote.enabled=false
spring.rabbitmq.ssl.verify-hostname=true
server.servlet.session.persistent=false
spring.devtools.remote.enabled=false 用于关闭远程 DevTools,同时应检查生产制品是否仍携带该依赖:
./mvnw -q dependency:tree -Dincludes=org.springframework.boot:spring-boot-devtools
server.servlet.session.persistent=false 会改变会话持久化行为,只能在确认业务允许后启用。无论采用哪一种临时措施,都应记录配置位置、负责人、启用时间和计划移除时间。
Actuator 临时处置需要 Spring Security 参与,不能只靠修改端点列表:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
随后按最小暴露原则限制端点,例如:
management.endpoints.web.exposure.include=health
management.endpoint.health.show-details=never
这只是暴露面基线,不是完整授权方案。env、configprops、loggers、shutdown 等敏感端点必须在 SecurityFilterChain 中配置明确的身份和权限要求;只有明确需要匿名访问的健康检查才能保留匿名策略。添加 Security 后还必须验证现有业务接口没有被错误拦截。
正式升级应修改实际管理 Spring Boot 版本的 parent、BOM 或 Gradle plugin。以 parent 为例:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>4.0.6</version>
<relativePath/>
</parent>
使用 Gradle plugin 时:
id 'org.springframework.boot' version '4.0.6'
不要只修改应用自身的展示版本,也不要在没有兼容性依据的情况下强行覆盖 Spring Boot 管理的传递依赖。完成版本修改后执行对应构建:
./mvnw clean verify
./gradlew clean build
升级运行时和服务器组件
Spring Boot 升级完成后,需要重新确认运行时和依赖树。Java 25 应安装官方发布的对应安全补丁构建,而不能只确认主版本号为 25。现有资料没有给出逐项 CVE 和受影响构建,因此升级单应记录“补丁来源、完整版本字符串、发布说明链接和验证结果”,而不是只写“已升级 Java 25”。
容器镜像也要同步更新。主机上执行 java -version 得到的结果不一定等于容器内 JVM 的版本;应分别进入实际运行实例核对 java.home 和运行时版本。如果一个部署单元包含多个进程,还要确认所有进程使用同一套补丁运行时。
传递依赖需要单独治理。Spring Boot BOM 管理的是一组兼容版本,不意味着所有第三方库都自动获得安全修复。应对 SBOM 中实际存在的组件逐项核对厂商公告,并优先通过直接依赖或受控 BOM 升级,而不是在构建脚本中零散强制覆盖版本。
升级顺序上,建议先完成框架和传递依赖修复,再单独接入 JDK 补丁或替换服务器组件。这样出现启动失败、反射调用变化或 TLS 行为差异时,才能判断回归来自哪一层。若业务窗口允许,JDK、框架和依赖应分阶段灰度,而不是在一次发布中同时改变所有变量。
封住业务代码里的高危入口
升级 Spring Boot 不会消除业务代码中的高危入口。资料将不安全反序列化、表达式注入和配置不当列为 Java 应用的重要风险入口;XXE 与 JNDI 注入则分别涉及外部实体解析和可控名称查找。
| 入口 | 输入前提 | 主要危害 | 修复方式 | 验证方式 |
|---|---|---|---|---|
| XXE | 用户可控 XML 到达解析器,解析器允许外部实体或 DTD | 读取本地文件、探测内网资源 | 禁用 DOCTYPE 和外部实体,按解析器配置安全特性 | 使用本地 canary 文件测试,解析器应拒绝或忽略外部实体 |
| JNDI 注入 | lookup 参数可被攻击者控制,可指向 RMI、LDAP 等远程目标 |
远程加载恶意对象或类,进一步执行代码 | 限制 JNDI 工厂和查找目标,查找名称只能来自可信业务映射 | 提交受控恶意 URL,确认没有外连、类加载或对象实例化 |
| 不安全反序列化 | 不可信序列化数据进入反序列化器,环境中存在可形成调用链的类 | 任意对象实例化、业务副作用,严重时可能执行代码 | 不反序列化不可信数据;使用类型白名单或 ObjectInputFilter 拒绝未批准类型 |
向测试端点发送白名单之外的探测对象,确认请求被拒绝 |
| 表达式注入 | 用户输入被直接拼接或作为表达式字符串求值 | 调用非预期方法、修改上下文或产生其他危险副作用 | 禁止求值不可信表达式,使用固定模板、参数化上下文和允许列表 | 构造无副作用攻击载荷,确认入口拒绝求值或只按固定规则处理 |
对于 DocumentBuilderFactory,资料给出的核心安全配置是禁用 DOCTYPE 及外部通用实体、外部参数实体:
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
使用 SAXParser 等其他解析器时,应配置对应的安全特性,不能假设一段 DocumentBuilderFactory 代码会自动覆盖所有 XML 入口。
XXE 回归测试只使用测试目录中的无敏感 canary 文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE test [
<!ENTITY xxe SYSTEM "file:///tmp/java-security-canary.txt">
]>
<test>&xxe;</test>
预期结果是解析失败,或实体内容没有被展开。JNDI 测试可使用不会连接外部主机的本地无效地址,例如 ldap://127.0.0.1:1/canary,并同时检查应用日志和网络连接。反序列化测试应使用专门构造的无害探测类型,而不是在生产环境尝试真实利用链。
校验 Undertow 的 Host 头
现有资料确认 Undertow 存在 CVSS 9.6 的 Host 头注入高危漏洞,但没有提供受影响版本和首个修复版本,因此不能给出未经官方公告验证的版本号,也不能仅凭应用“运行正常”判定不受影响。
先从实际依赖树中确认 Undertow 版本,再根据厂商公告选择已修复版本。修复版本进入项目后,还要在网关或反向代理层和应用层执行 Host 允许列表校验:请求的 Host 必须对应正式业务域名,内部服务域名、任意主机名和不符合路由配置的 Host 应被拒绝。
验证至少覆盖三个结果:异常 Host 无法进入业务路由,无法在响应或页面中生成基于该 Host 的链接,也无法借该请求触发后端服务调用。测试应同时覆盖直连应用端口和经过反向代理的路径,避免只在边缘层拦截而遗漏应用被直接访问的场景。
Host 校验规则应与实际部署域名绑定,不要复制包含示例域名的配置后直接上线。修复版本与 Host 校验是两层措施:前者消除组件缺陷,后者限制业务可接受的请求范围,两者不能互相替代。
用回归结果决定是否放量
升级后的验收应使用负向测试。只验证应用能够启动、首页能够打开,不能证明漏洞已经关闭。
| 验收对象 | 预期结果 |
|---|---|
| Spring Boot 版本 | 运行时和制品均为 4.0.6,依赖树没有旧版本残留 |
| Actuator | 匿名请求敏感端点得到 401、403 或 404,不返回环境变量、配置和管理操作能力 |
| Remote DevTools | 生产实例不监听远程调试端口,生产依赖中不存在 DevTools |
| RabbitMQ | 错误主机名或无效证书连接失败,正常连接和重连正常 |
| 随机数 | 敏感凭据不再来自 ${random.*},已轮换凭据有记录 |
| ApplicationTemp | 目录所有者正确、非运行账户不可写,目录劫持和会话伪造测试失败 |
| PID 文件 | 低权限用户不能预置或替换文件,应用不跟随异常符号链接 |
| XXE 与 JNDI | canary 文件不可读取,恶意查找地址不会产生外连或类加载 |
| 反序列化与表达式注入 | 非白名单类型和不可信表达式均被拒绝 |
| Undertow Host 校验 | 异常 Host 无法进入路由、生成链接或触发后端调用 |
| 业务兼容性 | 启动、健康检查、RabbitMQ、会话、文件路径和依赖调用均正常 |
Actuator 可以使用如下负向请求验证,地址和端口需要替换为实际管理端点:
curl -i --max-time 5 http://127.0.0.1:8080/actuator/env
预期不能获得敏感内容。若返回 401 或 403,说明授权生效;若返回 404,说明端点没有对外暴露,同样不能继续把管理端点绑定到公网或共享管理网络。
先在测试环境执行完整回归,再灰度发布。灰度期间重点观察启动失败、健康检查异常、HTTP 5xx、RabbitMQ 重连、会话读写、临时文件权限和网关 Host 拒绝日志。为每个指标设置明确阈值,并提前写清回滚条件;Java 25 安全更新也需要结合厂商兼容性说明进行验证。
如果已经出现入侵迹象,不能回滚到存在已知漏洞的旧 JAR、旧镜像或旧基础运行时。此时的回滚目标应是由可信环境重建、包含修复且完成凭据轮换的新制品。
留下可复查的关闭证据
关闭工单前至少保存八类材料:升级前后完整版本与镜像摘要、升级前后依赖树、SBOM、逐项 CVE 对照表、配置差异、负向测试与兼容性测试结果、灰度范围及监控数据、回滚条件和责任人。
其中,CVE 对照表必须区分“组件存在”“端口可达”“配置命中”和“已经出现利用迹象”,不能只记录一个扫描结果。临时措施还要标注负责人、启用原因和计划移除日期,避免半年后仍保留关闭远程调试、禁用会话持久化等高影响配置。
上述材料全部记录且相互一致后,工单才可标记为关闭。
[email protected]
。
我们承诺在核实信息后,将第一时间删除相关内容或断开链接。























暂无评论内容