一个搜得到的 5.3.41
Spring Framework 5.3 线的开源支持在 2024-08-31 结束,Maven Central 上 org.springframework 的 5.3 线终版是 5.3.39 。之后的 5.3.40 ~ 5.3.50,官方安全公告里都标着 Enterprise Support Only,只发给商业支持客户。
(这一点上一篇实测过:Spring 5.3.41 在哪下载?)
但如果你在 Central 上按版本搜 spring-core 的 5.3.4x,会搜到一个结果:
makefile
net.xdob.springframework:spring-core:5.3.41 2025-03-12
同一个 groupId 下一共 23 个构件,spring-web、spring-webmvc、spring-context、BOM 都有,版本是 5.3.39 和 5.3.41。在 Central 上,5.3.4x 的 Spring 只有这一家。
它下载下来的文件名是 spring-core-5.3.41.jar,MANIFEST 里写的是 Implementation-Version: 5.3.41,和官方构件的格式一模一样。放进项目里,凡是按 jar 文件名或 MANIFEST 认版本的工具,看到的都是「Spring 5.3.41」;只有去看 groupId 的,才会发现它不是 org.springframework。
那它到底是什么?
它是谁发的
打开 Central 上的 POM:
xml
<groupId>net.xdob.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.3.41</version>
<url>https://github.com/dibyang/spring-framework</url>
<organization>
<name>Spring IO</name>
</organization>
<developers>
<developer>
<id>jhoeller</id>
<name>Juergen Hoeller</name>
</developer>
</developers>
url 和 scm 指向的是 GitHub 上的 dibyang/spring-framework:一个从官方仓库 fork 出来的个人仓库,描述是 "Spring Framework for fix vulnerability"。organization 和 developers 沿用的是官方 POM 里的写法。
所以第一个结论:这是第三方基于官方源码自行重编、发到 Central 的,不是 Spring 官方发布。 仓库描述写得很清楚,它的目的就是给停更的 5.3 线补漏洞。
源码差了什么:6 个提交,1 个动了 Java
先确认官方 5.3.x 分支的状态:
bash
gh api repos/spring-projects/spring-framework/compare/v5.3.39...5.3.x
# ahead_by: 0
官方开源的 5.3.x 分支头就是 v5.3.39 标签,之后没有公开提交。
再比 fork 的 5.3.x 分支:
| 提交 | 内容 |
|---|---|
| add ali maven | 构建脚本 |
| v5.3.39 | 构建与发布配置 |
| v5.3.41-SNAPSHOT | 改版本号 |
| fix CVE-2024-38819 | 改了 WebMvc.fn / WebFlux.fn 的两个 PathResourceLookupFunction |
| v5.3.41 | 改版本号 |
| up | 发布配置 |
6 个提交里,只有 1 个改了 Java 代码。
逐字节比对:它和 5.3.39 有多少不同
光看提交不够,发到 Central 的 jar 才是真正进项目的东西。把 net.xdob 的 5.3.41 和官方 5.3.39 逐个类算 SHA-256:
| 构件 | 类总数 | 与官方 5.3.39 不同的类 |
|---|---|---|
| spring-core | 978 | 0 |
| spring-context | 892 | 0 |
| spring-webmvc | 557 | 1(PathResourceLookupFunction) |
| spring-webflux | --- | 1(PathResourceLookupFunction) |
spring-core 和 spring-context 与官方 5.3.39 逐字节相同。 这个 5.3.41 就是官方 5.3.39,加上一个补丁。
官方 5.3.41 修了两条,它只有一条
去 spring.io 看官方公告,修复版写着 5.3.41 的是这两条:
| CVE | 内容 | 官方 5.3 线修复版 | GitHub Advisory 严重度 | net.xdob 5.3.41 |
|---|---|---|---|---|
| CVE-2024-38819 | WebMvc.fn / WebFlux.fn 静态资源路径穿越 | 5.3.41(Enterprise Support Only) | high 7.5 | 有补丁(写法与官方不同,见下文) |
| CVE-2024-38820 | DataBinder 的 disallowedFields 大小写转换受 Locale 影响,字段可能没被挡住 |
5.3.41(Enterprise Support Only) | medium 5.3 | 没有 |
38820 的严重度不高,触发前提是应用用 setDisallowedFields 挡了某些字段。但问题不在这一条本身,而在于:版本号写着 5.3.41,却不包含官方 5.3.41 的全部修复。
少修的那条,在字节码里怎么认出来
38820 的官方补丁在 DataBinder 里。拿官方开源的 6.1.13(修复前)和 6.1.14(修复后)比:补丁把 toLowerCase() 换成了 toLowerCase(Locale.ROOT),于是类的常量池里多了对 java/util/Locale 的引用。
但只看这一个特征会误判。6.1.20 修 CVE-2025-22233 时,这段又被重构成 PatternMatchUtils.simpleMatchIgnoreCase,Locale 引用随之消失。补丁有两种字节码形态。
把 Central 上这几条线的开源版全扫一遍:
| 版本 | 引用 java/util/Locale |
引用 simpleMatchIgnoreCase |
|---|---|---|
| 5.3.36 ~ 5.3.39 | 无 | 无 |
| 6.0.20 ~ 6.0.23 | 无 | 无 |
| 6.1.10 ~ 6.1.13 | 无 | 无 |
| 6.1.14 ~ 6.1.19 | 有 | 无 |
| 6.1.20 ~ 6.1.21 | 无 | 有 |
| net.xdob 5.3.41 | 无 | 无 |
修复前的每一版两种都没有,修复后的每一版至少有一种。net.xdob 的 5.3.41 两种都没有,它的 DataBinder 本来就和 5.3.39 逐字节相同。
按版本号 5.3.41 对漏洞清单,会少算什么
很多团队的流程是:SCA 报出版本号,再拿版本号去对公告的影响区间。拿 5.3.41 去对,会得出「38819、38820 已修」,而实际只修了一条。
另外两件事也要一起看:
- CVE-2024-38816 (静态资源路径穿越,high 7.5)官方在 5.3.40 修。官方 6.1.13 的补丁是新增了
isInvalidEncodedInputPath方法,net.xdob的构件里没有这个方法,它是在apply里加了一次cleanPath。两种写法是否等效,本文没有验证。 - 5.3.41 之后官方又出了十几条 5.3 线的修复:CVE-2024-38828(5.3.42)、CVE-2025-22233(5.3.43)、CVE-2025-41242(5.3.44)、CVE-2025-41249(5.3.45),以及 2026-06-08 那批(5.3.49)和 2026-08-20 那批(5.3.50)。这个包发布于 2025-03,结构上一条都不可能包含。
顺带一个细节:一行调试输出
net.xdob 的 Spring MVC 补丁里,PathResourceLookupFunction.isInvalidPath 多了一行:
java
System.out.println("path = " + path);
如果你用函数式路由 RouterFunctions.resources(...) 发静态资源,每个命中该路由的请求路径都会打到标准输出。用传统 addResourceHandlers 配置的项目不走这段代码。这一行也正好成了认出这个构件的指纹:官方任何开源版的这个类里都没有 "path = " 这个字符串。
自己核:扫一下构件就知道
spring-cvss-check v0.3.0 加了「字节码核验」:不看版本号,直接看补丁在不在。
bash
java -jar spring-cvss-check.jar target/
# Spring Boot fat jar 也行,会打开 BOOT-INF/lib 里的依赖
java -jar spring-cvss-check.jar app.jar
扫到 net.xdob 的 5.3.41 时的输出:
ini
== 字节码核验:版本号说修了,补丁在不在 ==
[对不上] spring-context 5.3.41
版本号 5.3.41 按官方公告应已修 CVE-2024-38820,但 DataBinder 里**找不到这个补丁**
[对不上] spring-webmvc 5.3.41
带 net.xdob 第三方重编指纹:PathResourceLookupFunction.isInvalidPath 里有一行 System.out.println("path = " + path)
发布前拿官方开源 5.3.39、6.1.13、6.1.14、6.1.21 逐个跑过,核验项都是 0 条。第一版只认 Locale,把官方 6.1.21 误报成了补丁不在,上面那张两种形态的表就是修这个误报时扫出来的。核验只对 5.3 / 6.0 / 6.1 三条线下结论,6.2 以后不判。
纯 Java,零依赖,不联网。
这篇能证明什么、不能证明什么
能证明的:
- Central 上能下到的 Spring 5.3.41 来自第三方
net.xdob.springframework,不是官方发布; - 它的
spring-core、spring-context与官方 5.3.39 逐字节相同; - 官方 5.3.41 修的 CVE-2024-38820,它没有。
不能证明的:
- 不是说发布者有恶意。仓库描述写明了目的就是补漏洞,只是只补了一条;
- 不是说 38820 是高危。GitHub Advisory 标 medium,要求应用用了
disallowedFields; - 不是说它的 38819 补丁无效。写法和官方不同,等效与否没有验证;
- 官方商业版 5.3.41 的补丁长什么样,我们拿不到构件,上文的补丁形态只来自开源版。
实际建议只有一句:别把它当官方 5.3.41,别按这个版本号去对漏洞清单。