漏洞大多在依赖里
Java 应用的安全问题大多不出在业务代码,而在依赖组件:反序列化、表达式解析、日志组件,都出过影响面极大的漏洞。把应用目录下的 jar 清单导出并与安全公告对照,比笼统地“整体升级应用”更可执行,也能明确回答安全评审最常问的问题——上一次排查 fastjson、jackson、log4j 系列漏洞是什么时候。构建期导出依赖树是最优做法。
基本信息
| 适用平台 | Java 应用(Spring Boot、传统 war 部署、微服务) |
|---|---|
| 运行期手段 | 扫描应用目录的 jar 与 war 内嵌依赖 |
| 构建期手段 | mvn dependency:tree、gradle dependencies |
| 归档要求 | 依赖清单随发布产物存档 |
| 风险等级 | 中 |
典型使用场景
- 安全评审举证:说明依赖组件漏洞的排查范围与时间
- 漏洞应急:组件公告发布后立即定位受影响应用
- 上线前检查:新交付应用的依赖清单纳入交付物
- 遗留系统治理:多年未升级的应用按风险排序
- 交付验收:外包项目要求提供依赖清单作为验收条件
依赖清单导出
依赖清单导出
find /opt/app -name '*.jar' 2>/dev/null | sort | head -40
find /opt/app -name '*.jar' 2>/dev/null | wc -l
unzip -l /opt/app/app.war 2>/dev/null | grep 'WEB-INF/lib' | head -20
jar tf /opt/app/app.jar 2>/dev/null | grep 'BOOT-INF/lib' | head -20 # 嵌套依赖
# 构建期更优,把依赖树纳入发布产物:
# mvn dependency:tree > deps.txt
# gradle dependencies > deps.txt清单读法
| 清单来源 | 覆盖范围 | 注意点 |
|---|---|---|
| 应用 lib 目录 | 显式放置的依赖 | 可能含手工替换过的版本 |
| war 内 WEB-INF/lib | 打包内依赖 | 与共享库版本可能不同 |
| fat jar 的 BOOT-INF/lib | 内嵌全部依赖 | 需用 jar tf 或专用工具展开查看 |
| 依赖树文件 | 构建期声明的依赖 | 含传递依赖,最完整 |
| 容器层内 jar | 镜像内依赖 | 与源码仓库版本需交叉核对 |
安全评审最常问:你们上一次排查 fastjson、spring、log4j 系列漏洞是什么时候——构建期导出的依赖树存档就是最好的答案。
落地要点
- fat jar 内部依赖不透明:用 jar tf 或依赖分析工具展开,避免漏项
- 同名不同版本的 jar 共存时以运行中类路径为准,否则修了不生效
- 依赖清单与 CVE 库对照要有节奏:至少随每次构建与季度评审执行
- 升级依赖后要回归业务:反序列化类组件的行为差异可能影响接口
- 把清单纳入发布产物存档,形成可追溯的版本历史
依赖升级属于应用变更:中间件与工具库版本跳跃时,需在测试环境完成接口与性能回归,不能直接在生产替换 jar。