版本说明:本文基于 Dependency-Check 12.1.0 版本编写。请注意,该项目已于 2025 年 9 月 27 日归档,不再维护,但现有版本仍可正常使用。
文章目录
-
- 📄 文档概述
- 引言
- 第一部分:Dependency-Check 基础
-
- 1.1 Dependency-Check 是什么?为什么你需要它?
- 1.2 为什么需要 SCA(软件成分分析)
- 1.3 Dependency-Check 工作原理
- 1.4 漏洞数据库与 CVSS 评分体系
- 第二部分:安装与基础使用
-
- 2.1 环境准备
- 2.2 命令行使用方式
- 2.3 Docker 方式使用
- 2.4 配置文件详解
- 第三部分:全栈集成实战
-
- 3.1 Java/Maven 项目集成
- 3.2 前端/npm 项目集成
- 3.3 Jenkins CI/CD 集成
- 3.4 与 SonarQube 联动
- 第四部分:高级配置与最佳实践
-
- 4.1 扫描规则与阈值配置
- 4.2 抑制文件(Suppression)管理误报
- 4.3 报告解析与结果处理
- 4.4 性能优化
- 第五部分:完整项目案例
-
- 5.1 项目背景与架构
- 5.2 后端 Maven 配置
- 5.3 前端 npm 配置
- 5.4 Jenkins Pipeline 完整配置
- 5.5 生产级 Pipeline 实践(多模块 + 条件执行)
- 5.6 前端项目 Pipeline 实践(Node.js + CLI 工具)
- 5.7 NVD 数据库定时更新 Job
- 5.8 安全门禁与质量门禁
- 5.9 漏洞修复流程
- 第六部分:DevSecOps 扩展
-
- 6.1 与 DAST、SAST 工具的配合
- 6.2 容器安全扫描(Trivy)集成
- 6.3 安全运营与持续改进
- 第七部分:常见问题与故障排查
-
- Q1:首次扫描为什么这么慢?
- Q2:如何处理误报?
- Q3:内网环境如何使用?
- Q4:扫描失败怎么办?
- Q5:如何提升扫描速度?
- Q6:如何集成到现有的 CI/CD 流程?
- Q7:如何设置安全门禁?
- Q8:如何处理大型项目的扫描?
- 结语
- 参考资料
📄 文档概述
- 创建时间:2026-02-06
- 作者:zuozewei
- 功能:DevSecOps 安全实践完整指南,以 Dependency-Check 为核心
- 技术栈:Dependency-Check、Maven、npm、Jenkins、Docker、SonarQube、Trivy
- 项目路径:https://github.com/zuozewei/blog-example/tree/master/Jenkins-ci/devsecops-dependency-check-guide
引言
还记得 Log4j2 漏洞爆发那天吗?2021 年 12 月,整个技术圈都炸了——一个看似普通的日志库,竟然能让全球数百万应用瞬间沦陷。那天晚上,我们团队紧急排查了所有项目,发现竟然有 15 个应用都用了这个"定时炸弹"。
这就是现实:一个普通的 Java 企业级应用,平均依赖超过 100 个第三方库,而这些依赖的依赖又会引入数百个间接依赖。任何一个环节出问题,都可能成为攻击者的突破口。
今天聊聊 OWASP Dependency-Check——这个开源的软件成分分析工具,如何帮你提前发现这些"定时炸弹",把它们扼杀在摇篮里。
第一部分:Dependency-Check 基础
1.1 Dependency-Check 是什么?为什么你需要它?
先说结论:如果你的项目用了第三方依赖(99% 的项目都是),那你就需要 SCA 工具。而 Dependency-Check,就是开源世界里最好用的那个。
OWASP Dependency-Check 是一个开源的**软件成分分析(Software Composition Analysis, SCA)**工具,由 OWASP(开放式 Web 应用程序安全项目)维护。它能够自动检测应用程序依赖项中已知的公开安全漏洞。
⚠️ 重要提示:该项目已于 2025 年 9 月 27 日归档,不再进行主动维护。本文基于最后一个稳定版本 12.1.0(2025 年 2 月 17 日发布)编写。现有版本仍可正常使用,但建议关注其他活跃维护的替代方案,如:
- Snyk(商业,有免费版)
- Trivy(开源,支持容器和依赖扫描)
- Grype(开源,专注于漏洞扫描)
核心能力:
- 自动识别项目使用的第三方依赖(直接和传递依赖)
- 与 NVD(National Vulnerability Database)等漏洞数据库比对
- 生成详细的漏洞报告,包含 CVE 编号、CVSS 评分、修复建议
- 支持多种编程语言和构建工具
支持的语言与平台:
| Java | JAR, WAR, EAR, pom.xml | 完整的 Maven/Gradle 支持 |
| JavaScript/Node.js | package.json, package-lock.json, npm-shrinkwrap.json | 前端和 Node.js 项目 |
| Python | requirements.txt, setup.py, Pipfile | Python 依赖分析 |
| .NET | packages.config, .csproj, .vbproj | .NET Framework 和 Core |
| Ruby | Gemfile, Gemfile.lock | Ruby 项目 |
| Go | go.mod, go.sum | Go 模块支持 |
| PHP | composer.json, composer.lock | PHP 项目 |
| C/C++ | 源代码分析 | 有限支持 |
1.2 为什么需要 SCA(软件成分分析)
🤔 思考一下:
你的项目有多少个依赖?你能说出每个依赖的版本吗?如果其中一个依赖被发现有严重漏洞,你能在多长时间内发现并修复?
开源依赖的安全现状:
根据 Sonatype 发布的《软件供应链状况报告》,现状不容乐观:
- 现代应用程序中 70-90% 的代码来自第三方开源组件
- 96% 的下载存在已知漏洞的组件版本
- 29% 的热门项目包含至少一个已知漏洞的依赖
- 2023 年开源供应链攻击增长了 742%
这些数字背后,是无数个潜在的安全漏洞。
真实案例:
- Log4j2 漏洞(CVE-2021-44228):影响全球数百万应用,CVSS 评分 10.0(最高危)
- Spring4Shell(CVE-2022-22965):Spring Framework 核心漏洞,影响大量 Java 应用
- XZ 后门事件(2024):一个被广泛使用的压缩库被植入后门,险些成为史上最严重的供应链攻击
这些事件凸显了 SCA 工具的必要性。
只有持续监控依赖安全,才能在漏洞被利用前及时发现并修复。
1.3 Dependency-Check 工作原理
Dependency-Check 的工作流程可分为四个阶段:
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ 1. 依赖识别 │ → │ 2. 特征提取 │ → │ 3. 漏洞匹配 │ → │ 4. 报告生成 │
└─────────────────┘ └─────────────────┘ └─────────────────┘ └─────────────────┘
阶段一:依赖识别——“你是谁?”
这一步就像是在做人口普查。工具会扫描你的项目文件(pom.xml、package.json 等),把所有依赖都揪出来——无论是直接依赖还是传递依赖,一个都跑不掉。
实际踩坑发现:有些项目会通过本地 JAR 包引入依赖,这种情况下 Dependency-Check 可能会漏掉。如果你有这种情况,记得手动指定扫描路径。
阶段二:特征提取——“你的特征是什么?”
拿到依赖列表后,工具开始提取每个依赖的"身份证"信息:
- Maven:groupId:artifactId:version
- npm:package@version
- PyPI:package==version
同时还会计算文件哈希值(SHA1、MD5)和提取 CPE 标识符。这就像给每个人拍照、录指纹,确保后续能准确识别。
阶段三:漏洞匹配——“你有没有案底?”
有了特征信息,工具就开始查"案底"了——将这些特征与漏洞数据库比对。
主要数据源包括:
- NVD:美国国家标准与技术研究院维护的官方漏洞库
- RetireJS:JavaScript 特定漏洞库
- Node Security Platform:Node.js 漏洞数据
工具使用 Lucene 索引实现高效匹配,就像警察查数据库一样快。
阶段四:报告生成——“给你看证据”
最后一步,工具会生成详细的"调查报告",包含:
- 漏洞详情(CVE 编号、CVSS 评分)
- 修复建议(升级到哪个版本)
- 支持多种格式(HTML、XML、JSON、CSV)
如果发现误报,还可以通过抑制文件排除——就像警察撤销错误的案底记录。
1.4 漏洞数据库与 CVSS 评分体系
NVD(National Vulnerability Database) NVD 是美国国家标准与技术研究院(NIST)维护的漏洞数据库,包含:
- CVE(Common Vulnerabilities and Exposures)标识符
- CPE(Common Platform Enumeration)标识符
- CVSS(Common Vulnerability Scoring System)评分
- 漏洞描述、参考链接、修复信息
CVSS 评分体系: CVSS 是业界通用的漏洞严重程度评估标准,目前主要使用 v3.1 版本。
| 0.0 | None | 无风险 |
| 0.1 – 3.9 | Low | 按计划修复 |
| 4.0 – 6.9 | Medium | 优先修复 |
| 7.0 – 8.9 | High | 尽快修复,考虑阻断发布 |
| 9.0 – 10.0 | Critical | 立即修复,必须阻断发布 |
CVSS 评分维度:
- 基础评分(Base Score):漏洞本身的固有特征
- 攻击向量(网络/本地/物理)
- 攻击复杂度
- 所需权限
- 用户交互要求
- 影响范围
- 机密性/完整性/可用性影响
- 时效评分(Temporal Score):随时间变化的特征
- 环境评分(Environmental Score):特定环境的影响
在 DevSecOps 实践中,通常使用基础评分作为质量门禁的阈值依据。
🤔 思考一下:
如果你的项目发现了 CVSS 9.0 的严重漏洞,你会怎么做?是立即修复还是先评估影响?
第二部分:安装与基础使用
2.1 环境准备
系统要求:
| Java 版本 | Java 8 | Java 11+ |
| 内存 | 2GB | 4GB+ |
| 磁盘空间 | 2GB | 10GB+(用于缓存漏洞数据库) |
| 网络 | 需要连接 NVD | 稳定连接,建议申请 API Key |
NVD API Key 申请(强烈推荐):
💡 小贴士: NVD API Key 是免费的,但申请需要几天时间。建议提前申请,避免临时抱佛脚。
NVD API 限制(2024 年更新):
- 无 API Key:每分钟 5 次请求
- 有 API Key:每分钟 50 次请求
- 每日配额:5,000 次请求(有 API Key)
- 注意:NVD 偶尔会临时调整限制,建议关注官方公告
未使用 API Key 时,首次下载漏洞数据库可能需要数小时。申请 API Key 后可大幅提升下载速度。
📖 点击展开:NVD API Key 详细申请步骤
⚠️ 注意事项:
- API Key 是 40 字符的十六进制字符串
- 每个组织/个人只能申请一个 Key
- 不要共享 API Key,避免超过速率限制
- 使用 API Key 的产品需要显示声明:“This product uses the NVD API but is not endorsed or certified by NVD.”
2.2 命令行使用方式
下载与安装:
# 下载最新版本(以 12.1.0 为例)
wget https://github.com/jeremylong/DependencyCheck/releases/download/v12.1.0/dependency-check-12.1.0-release.zip || {
echo "错误:下载失败,请检查网络连接"
exit 1
}
# 解压
unzip dependency-check-12.1.0-release.zip -d /opt/dependency-check || {
echo "错误:解压失败"
exit 1
}
# 添加到 PATH(Linux/Mac)
export PATH=$PATH:/opt/dependency-check/bin
# 验证安装
dependency-check.sh –version || {
echo "错误:安装验证失败"
exit 1
}
echo "✅ Dependency-Check 安装成功"
首次运行(更新漏洞数据库):
# 仅更新数据库(推荐首次运行)
dependency-check.sh –nvdApiKey YOUR_API_KEY –updateonly || {
echo "错误:数据库更新失败"
echo "请检查:"
echo "1. NVD API Key 是否正确"
echo "2. 网络连接是否正常"
exit 1
}
基础扫描命令:
# 基础扫描
dependency-check.sh \\
–project "MyApplication" \\
–scan "/path/to/project" \\
–out "/path/to/reports" \\
–format HTML
# 完整参数示例
dependency-check.sh \\
–project "E-Commerce Platform" \\
–scan "/workspace/ecommerce" \\
–out "/reports/dependency-check" \\
–format ALL \\
–nvdApiKey YOUR_API_KEY \\
–failOnCVSS 7 \\
–enableExperimental
常用参数说明:
| –project | -p | 项目名称 | –project “MyApp” |
| –scan | -s | 扫描路径(可多次指定) | –scan ./lib –scan ./src |
| –out | -o | 输出目录 | –out ./reports |
| –format | -f | 报告格式(HTML/XML/JSON/CSV/ALL) | –format ALL |
| –failOnCVSS | CVSS 阈值(超过则返回非0) | –failOnCVSS 7 | |
| –suppression | 抑制文件路径 | –suppression suppress.xml | |
| –nvdApiKey | NVD API 密钥 | –nvdApiKey xxx | |
| –enableExperimental | 启用实验性分析器 | ||
| –disableRetireJS | 禁用 RetireJS 分析器 | ||
| –disableNodeJS | 禁用 Node.js 分析器 |
📌 本节要点:
- ✅ 首次运行记得用 –updateonly 更新数据库
- ✅ 生产环境务必申请 NVD API Key
- ✅ 使用 –failOnCVSS 7 设置安全门禁
- ✅ 抑制文件可以处理误报,但不要滥用
⚠️ 避坑指南:
- 不要在 CI/CD 中使用 –updateonly,会拖慢构建速度
- Windows 用户注意路径分隔符问题
- 首次扫描需要下载完整数据库(约2GB),耐心等待
2.3 Docker 方式使用
Docker 方式是使用 Dependency-Check 最便捷的方式,无需本地安装,适合 CI/CD 场景。
基础使用:
# 拉取镜像
docker pull owasp/dependency-check:latest
# 基础扫描
docker run –rm \\
-v $(pwd):/src \\
-v $(pwd)/reports:/report \\
owasp/dependency-check:latest \\
–scan /src \\
–format ALL \\
–project "MyProject" \\
–out /report
带数据缓存的优化方案:
#!/bin/bash
# dependency-check.sh – 封装脚本
set -e # 遇到错误立即退出
DC_VERSION="latest"
DC_DIRECTORY="$HOME/OWASP-Dependency-Check"
DATA_DIRECTORY="$DC_DIRECTORY/data"
REPORT_DIRECTORY="$(pwd)/reports"
# 检查 NVD API Key
if [ -z "${NVD_API_KEY}" ]; then
echo "错误:未设置 NVD_API_KEY 环境变量"
echo "请先设置:export NVD_API_KEY=your_api_key"
exit 1
fi
# 创建必要目录
echo "创建数据目录:$DATA_DIRECTORY"
mkdir -p "$DATA_DIRECTORY" || {
echo "错误:创建数据目录失败"
exit 1
}
echo "创建报告目录:$REPORT_DIRECTORY"
mkdir -p "$REPORT_DIRECTORY" || {
echo "错误:创建报告目录失败"
exit 1
}
# 运行扫描
echo "开始扫描项目:$(basename $(pwd))"
docker run –rm \\
-e user=$USER \\
-u $(id -u ${USER}):$(id -g ${USER}) \\
–volume $(pwd):/src:ro \\
–volume "$DATA_DIRECTORY":/usr/share/dependency-check/data:rw \\
–volume "$REPORT_DIRECTORY":/report:rw \\
owasp/dependency-check:$DC_VERSION \\
–nvdApiKey ${NVD_API_KEY} \\
–scan /src \\
–format "ALL" \\
–project "$(basename $(pwd))" \\
–out /report \\
–failOnCVSS 7 || {
echo "错误:依赖扫描失败"
exit 1
}
echo "扫描完成!报告已保存到:$REPORT_DIRECTORY"
数据持久化的重要性:
- 漏洞数据库(~2GB)只需定期更新,无需每次重新下载
- 使用本地卷映射缓存数据,大幅提升后续扫描速度
- 建议设置定时任务(cron)定期更新数据库
实战经验分享:
我们团队刚开始用 Docker 方式时,遇到过一个坑:每次构建都重新下载漏洞数据库,导致构建时间从 5 分钟暴涨到 30 分钟。
后来发现,只需要把数据目录挂载到宿主机,问题就解决了。这就是上面提供的优化方案——现在我们的构建时间稳定在 8 分钟左右。
另一个小技巧: 如果你的 Jenkins 节点资源有限,可以考虑使用 Docker 的 –memory 参数限制内存占用:
docker run –rm \\
–memory="2g" \\
–memory-swap="2g" \\
-v $(pwd):/src \\
-v $(pwd)/dc-data:/usr/share/dependency-check/data \\
owasp/dependency-check:latest \\
–scan /src
还有个踩坑记录: Windows 环境下使用 Docker 时,路径映射可能会出问题。记得用正斜杠 / 而不是反斜杠 \\,或者使用 $(pwd) 让系统自动处理路径转换。
# Windows PowerShell – 正确写法
docker run –rm `
-v "${PWD}:/src" `
-v "${PWD}\\dc-data:/usr/share/dependency-check/data" `
owasp/dependency-check:latest `
–scan /src
# 错误写法(会导致路径问题)
docker run –rm \\
-v "C:\\project:/src" \\
owasp/dependency-check:latest \\
–scan /src
2.4 配置文件详解
Dependency-Check 支持通过属性文件进行配置,便于团队统一管理和版本控制。
配置文件位置:
- 命令行:–propertyfile /path/to/config.properties
- 默认查找:dependency-check.properties(当前目录或 classpath)
完整配置示例(dependency-check.properties):
# ===========================================
# OWASP Dependency-Check 配置文件
# ===========================================
# NVD 配置
nvd.api.key=YOUR_NVD_API_KEY_HERE
nvd.api.delay=2000
nvd.api.validforhours=24
# 数据目录
data.directory=/opt/dependency-check/data
# 报告配置
report.output.directory=./reports
report.format=HTML,JSON
# 扫描配置
scan.depth=10
analyzer.archive.enabled=true
analyzer.jar.enabled=true
analyzer.maven.enabled=true
analyzer.npm.enabled=true
analyzer.python.enabled=true
analyzer.ruby.gemspec.enabled=true
# 抑制文件
suppression.file=./dependency-check-suppressions.xml
# 网络配置
proxy.server=proxy.company.com
proxy.port=8080
proxy.username=${PROXY_USER}
proxy.password=${PROXY_PASS}
# 失败阈值
fail.on.cvss=7
# 高级配置
analyzer.dependencybundling.enabled=true
analyzer.dependencymerging.enabled=true
使用配置文件:
dependency-check.sh –propertyfile dependency-check.properties –scan ./project
📌 本节要点:
- ✅ 配置文件便于团队统一管理和版本控制
- ✅ 敏感信息(API Key)使用环境变量 ${env.VAR_NAME}
- ✅ 代理配置适合内网环境
- ✅ 抑制文件路径可以相对路径或绝对路径
⚠️ 避坑指南:
- 不要把 API Key 直接写在配置文件里,用环境变量
- 配置文件要纳入版本控制,但敏感信息除外
- 代理配置只在需要时启用,否则会影响性能
第三部分:全栈集成实战
3.1 Java/Maven 项目集成
Maven 是 Java 项目最常用的构建工具,Dependency-Check 提供了完善的 Maven 插件支持。
基础配置(pom.xml):
<project>
…
<build>
<plugins>
<!– OWASP Dependency-Check Plugin –>
<plugin>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId>
<version>12.1.0</version>
<configuration>
<!– NVD API Key –>
<nvdApiKey>${nvd.api.key}</nvdApiKey>
<!– 失败阈值:CVSS >= 7 时构建失败 –>
<failBuildOnCVSS>7</failBuildOnCVSS>
<!– 输出格式 –>
<format>ALL</format>
<!– 输出目录 –>
<outputDirectory>${project.build.directory}/dependency-check</outputDirectory>
<!– 抑制文件 –>
<suppressionFiles>
<suppressionFile>dependency-check-suppressions.xml</suppressionFile>
</suppressionFiles>
<!– 扫描选项 –>
<skipProvidedScope>false</skipProvidedScope>
<skipRuntimeScope>false</skipRuntimeScope>
<skipTestScope>true</skipTestScope>
<!– 启用实验性分析器 –>
<enableExperimental>true</enableExperimental>
</configuration>
<executions>
<execution>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<!– 属性配置 –>
<properties>
<nvd.api.key>${env.NVD_API_KEY}</nvd.api.key>
</properties>
</project>
多模块项目配置:
对于多模块 Maven 项目,建议在父 POM 中统一配置:
<project>
<groupId>com.company</groupId>
<artifactId>parent-project</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>
<modules>
<module>module-a</module>
<module>module-b</module>
<module>module-c</module>
</modules>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId>
<version>12.1.0</version>
<configuration>
<nvdApiKey>${nvd.api.key}</nvdApiKey>
<failBuildOnCVSS>7</failBuildOnCVSS>
<format>ALL</format>
<!– 聚合报告 –>
<aggregate>true</aggregate>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
常用 Maven 命令:
💡 提示:以下命令是 Dependency-Check Maven 插件的基础用法。更多高级用法和 Pipeline 集成示例,请参考第五部分的完整项目案例。
# 运行依赖扫描
mvn dependency-check:check
# 仅更新漏洞数据库
mvn dependency-check:update-only
# 聚合多模块报告
mvn dependency-check:aggregate
# 跳过检查(紧急情况)
mvn clean package -Ddependency-check.skip=true
# 仅生成报告,不失败构建
mvn dependency-check:check -DfailBuildOnCVSS=11
命令说明:
- dependency-check:check:执行完整的依赖扫描并生成报告
- dependency-check:update-only:仅更新 NVD 漏洞数据库,不执行扫描
- dependency-check:aggregate:聚合多模块项目的扫描结果
- -Ddependency-check.skip=true:跳过依赖扫描(紧急情况使用)
- -DfailBuildOnCVSS=11:设置 CVSS 阈值,超过则构建失败(11 表示不失败)
📖 相关章节:
- 5.2 节:后端 Maven 完整配置示例
- 5.4 节:Jenkins Pipeline 中的 Maven 集成
- 5.9 节:漏洞修复实战案例
实战经验分享:
我们团队在集成 Maven 插件时,遇到过几个典型问题,分享给大家:
问题一:多模块项目扫描时间过长
有个 20 个模块的微服务项目,每次全量扫描都要 40 分钟。后来我们采用了分层扫描策略:
# 核心模块(每次 CI 都扫)
mvn -f core/pom.xml dependency-check:check
# 业务模块(按需扫描,只扫变更的)
git diff –name-only HEAD~1 HEAD | grep "pom.xml" | while read pom; do
module_dir=$(dirname "$pom")
mvn -f "$module_dir/pom.xml" dependency-check:check
done
这样把平均扫描时间降到了 15 分钟左右。
问题二:NVD API Key 在 CI 环境中泄露
一开始我们把 API Key 直接写在 pom.xml 里,结果代码仓库被公开后,Key 就泄露了。正确做法是通过环境变量传递:
<properties>
<nvd.api.key>${env.NVD_API_KEY}</nvd.api.key>
</properties>
然后在 Jenkins 中配置 Credentials:
environment {
NVD_API_KEY = credentials('nvd-api-key')
}
问题三:内存溢出(OutOfMemoryError)
大项目扫描时经常遇到内存溢出,特别是在 Jenkins 节点资源有限的情况下。解决方案是增加 JVM 内存:
<plugin>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId>
<configuration>
<jvmArgs>-Xmx4g -Xms2g</jvmArgs>
</configuration>
</plugin>
或者在命令行中设置:
export MAVEN_OPTS="-Xmx4g -Xms2g"
mvn dependency-check:check
问题四:抑制文件管理混乱
刚开始大家随便加抑制规则,结果有些真正的漏洞被抑制了。后来我们建立了严格的审批流程:
<suppress>
<notes><![CDATA[
审批人:张三
审批日期:2024-01-15
原因:测试依赖,生产环境不受影响
计划移除:2024-06-01
]]></notes>
<packageUrl regex="true">^pkg:maven/org\\.junit/.*$</packageUrl>
</suppress>
还有一个实用技巧: 在本地开发时,可以临时跳过依赖扫描来加快构建速度:
# 本地开发快速构建
mvn clean package -Ddependency-check.skip=true
# 提交前再运行完整检查
mvn dependency-check:check
3.2 前端/npm 项目集成
前端项目通常使用 npm/yarn 管理依赖,Dependency-Check 通过分析 package.json 和 lock 文件来识别依赖。
Node.js 扫描配置:
# 命令行扫描 Node.js 项目
dependency-check.sh \\
–project "Frontend App" \\
–scan ./package.json \\
–scan ./package-lock.json \\
–out ./reports \\
–format ALL \\
–enableExperimental
npm 脚本集成(package.json):
{
"name": "my-frontend-app",
"version": "1.0.0",
"scripts": {
"security:check": "dependency-check –scan package.json –scan package-lock.json –format HTML –out reports",
"security:check-ci": "dependency-check –scan package.json –scan package-lock.json –format JSON –failOnCVSS 7",
"prepush": "npm run security:check-ci"
},
"devDependencies": {
"dependency-check": "^5.0.0"
}
}
与 npm audit 的对比:
| 数据源 | npm 仓库 | NVD + RetireJS + 其他 |
| 漏洞覆盖 | npm 包 | 多语言、多平台 |
| 报告格式 | 命令行/JSON | HTML/XML/JSON/CSV |
| CI/CD 集成 | 基础 | 完善 |
| 抑制机制 | 简单 | 强大的抑制文件 |
最佳实践: 建议同时使用 npm audit 和 Dependency-Check,两者互补:
- npm audit:快速检查,npm 特定漏洞
- Dependency-Check:全面扫描,统一报告
实战经验分享:
前端项目的依赖扫描有几个特殊之处,这里分享一些踩坑经验:
问题一:package-lock.json 和 yarn.lock 冲突
有些项目同时存在 package-lock.json 和 yarn.lock,导致 Dependency-Check 扫描结果不一致。我们团队的做法是:
# 只保留一个 lock 文件
yarn.lock
# package-lock.json 保留
问题二:devDependencies 误报
开发依赖(如 eslint、webpack)经常报出漏洞,但生产环境根本用不到。可以在 package.json 中配置:
{
"scripts": {
"security:check": "dependency-check –scan package.json –scan package-lock.json –format HTML –out reports –exclude devDependencies"
}
}
或者在抑制文件中排除:
<suppress>
<notes><![CDATA[
开发依赖,生产环境不受影响
]]></notes>
<packageUrl regex="true">^pkg:npm/webpack@.*$</packageUrl>
</suppress>
问题三:私有 npm 包扫描失败
公司内部搭建的私有 npm 仓库,Dependency-Check 无法识别。解决方案:
<suppress>
<notes><![CDATA[
私有 npm 包,已通过内部安全审查
]]></notes>
<packageUrl regex="true">^pkg:npm/@company/.*$</packageUrl>
</suppress>
问题四:Monorepo 项目扫描慢
对于使用 lerna、nx 等 Monorepo 工具的项目,全量扫描非常慢。我们采用增量扫描:
# 只扫描变更的包
CHANGED_PACKAGES=$(lerna changed –json | jq -r '.[].location')
for pkg in $CHANGED_PACKAGES; do
dependency-check.sh \\
–project "$(basename $pkg)" \\
–scan "$pkg/package.json" \\
–scan "$pkg/package-lock.json" \\
–out "reports/$(basename $pkg)"
done
还有一个实用技巧: 结合 Husky 在 git commit 前自动检查:
{
"husky": {
"hooks": {
"pre-commit": "npm run security:check"
}
}
}
这样可以在代码提交前就发现问题,而不是等到 CI 阶段才发现。
📌 本节要点:
- ✅ 前端项目建议同时使用 npm audit 和 Dependency-Check
- ✅ 明确锁定一个包管理器(推荐 npm)
- ✅ 开发依赖可以通过抑制文件或配置排除
- ✅ 私有 npm 包需要在抑制文件中排除
⚠️ 避坑指南:
- 不要同时存在 package-lock.json 和 yarn.lock
- devDependencies 漏洞可以忽略,但要记录原因
- Monorepo 项目采用增量扫描,避免全量扫描
- Husky 可以在提交前发现问题,但会增加提交时间
3.3 Jenkins CI/CD 集成
Jenkins 是 DevSecOps 实践中使用最广泛的 CI 工具。本节介绍基础集成方案,完整的生产级 Pipeline 示例请参考第五部分。
插件安装:
全局工具配置:
- Name: dependency-check
- Install automatically: 勾选
- Version: 选择最新版本
基础 Pipeline 示例:
pipeline {
agent any
environment {
NVD_API_KEY = credentials('nvd-api-key')
}
tools {
maven 'maven-3.9'
jdk 'jdk-17'
dependencyCheck 'dependency-check'
}
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Build') {
steps {
sh 'mvn clean compile -DskipTests'
}
}
stage('Security Scan') {
steps {
dependencyCheck additionalArguments: """
–project "${env.JOB_NAME}"
–scan ./
–format HTML
–format XML
–failOnCVSS 7
–nvdApiKey ${NVD_API_KEY}
""",
odcInstallation: 'dependency-check'
}
}
stage('Package') {
steps {
sh 'mvn package -DskipTests'
}
}
}
post {
always {
dependencyCheckPublisher pattern: 'dependency-check-report.xml'
archiveArtifacts artifacts: 'dependency-check-report.*', allowEmptyArchive: true
}
}
}
Pipeline 关键点说明:
| credentials('nvd-api-key') | 从 Jenkins Credentials 中安全获取 API Key |
| –failOnCVSS 7 | CVSS >= 7 时命令返回非0,导致阶段失败 |
| dependencyCheckPublisher | 在 Jenkins UI 中显示漏洞趋势图 |
📖 进阶内容:
- 5.4 节:完整的多模块项目 Pipeline 配置
- 5.5 节:生产级 Pipeline(条件执行、多环境)
- 5.6 节:前端项目 Pipeline 实践(Node.js + CLI 工具)
3.4 与 SonarQube 联动
SonarQube 是最流行的代码质量平台,将 Dependency-Check 报告导入 SonarQube 可以实现统一的质量视图。
配置步骤:
安装 SonarQube 插件
- 进入 SonarQube Administration → Marketplace
- 安装 “Dependency-Check” 插件
- 重启 SonarQube
Maven 配置(pom.xml):
<profiles>
<profile>
<id>sonar</id>
<build>
<plugins>
<!– Dependency-Check –>
<plugin>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId>
<version>12.1.0</version>
<configuration>
<format>XML</format>
<outputDirectory>${project.build.directory}</outputDirectory>
</configuration>
</plugin>
<!– SonarQube –>
<plugin>
<groupId>org.sonarsource.scanner.maven</groupId>
<artifactId>sonar-maven-plugin</artifactId>
<version>3.9.1.2184</version>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<properties>
<!– SonarQube 配置 –>
<sonar.host.url>http://sonarqube.company.com:9000</sonar.host.url>
<sonar.dependencyCheck.reportPath>${project.build.directory}/dependency-check-report.xml</sonar.dependencyCheck.reportPath>
<sonar.dependencyCheck.htmlReportPath>${project.build.directory}/dependency-check-report.html</sonar.dependencyCheck.htmlReportPath>
</properties>
# 运行 Dependency-Check
mvn dependency-check:check
# 上传到 SonarQube
mvn sonar:sonar -Dsonar.login=YOUR_TOKEN
- 进入 SonarQube 项目页面
- 在 “Measures” → “Dependencies” 中查看漏洞统计
- 点击具体依赖查看详细漏洞信息
集成效果:
- 统一查看代码质量和依赖安全
- 利用 SonarQube 的权限管理和通知功能
- 在 SonarQube 仪表盘中跟踪安全债务
第四部分:高级配置与最佳实践
4.1 扫描规则与阈值配置
CVSS 阈值策略:
在 DevSecOps 实践中,建议采用渐进式阈值策略:
// Jenkins Pipeline 中的渐进式阈值
stage('Security Gate') {
steps {
script {
def report = readJSON file: 'dependency-check-report.json'
def vulnerabilities = report.dependencies.collectMany { it.vulnerabilities ?: [] }
def critical = vulnerabilities.count { it.cvssv3?.baseScore >= 9.0 }
def high = vulnerabilities.count { it.cvssv3?.baseScore >= 7.0 }
def medium = vulnerabilities.count { it.cvssv3?.baseScore >= 4.0 }
// 严重漏洞:零容忍
if (critical > 0) {
error "❌ 发现 ${critical} 个严重漏洞,必须立即修复!"
}
// 高危漏洞:允许少量,需审批
if (high > 3) {
input message: "发现 ${high} 个高危漏洞,是否继续部署?",
ok: '确认部署',
submitterParameter: 'APPROVER'
}
// 中危漏洞:记录并跟踪
if (medium > 10) {
unstable "⚠️ 中危漏洞较多(${medium}个),建议安排修复"
}
echo "✅ 安全门禁通过"
}
}
}
按环境设置不同阈值:
// 根据分支设置不同严格程度
def getCVSSThreshold() {
switch(env.BRANCH_NAME) {
case 'main':
case 'master':
return 5 // 生产分支严格
case 'release/*':
return 7 // 发布分支适中
default:
return 9 // 特性分支宽松
}
}
stage('Security Scan') {
steps {
dependencyCheck additionalArguments: """
–failOnCVSS ${getCVSSThreshold()}
…
"""
}
}
4.2 抑制文件(Suppression)管理误报
抑制文件用于排除误报或已知不适用于当前场景的漏洞,是 DevSecOps 实践中的必备技能。
抑制文件结构:
<?xml version="1.0" encoding="UTF-8"?>
<suppressions xmlns="https://jeremylong.github.io/DependencyCheck/dependency-suppression.1.3.xsd">
<!– ============================================ –>
<!– 抑制规则说明: –>
<!– 1. 每个 suppress 元素对应一条抑制规则 –>
<!– 2. 必须包含 notes 说明抑制原因 –>
<!– 3. 建议包含审核日期和审核人 –>
<!– 4. 定期审查抑制规则(建议每季度) –>
<!– ============================================ –>
<!– 示例1:按 CVE 编号抑制特定漏洞 –>
<suppress>
<notes><![CDATA[
[抑制原因] CVE-2021-1234 是误报
[分析详情] 该漏洞影响的是 log4j 1.x,而我们使用的是 log4j 2.x
[审核日期] 2024-01-15
[审核人] 张三
[下次审查] 2024-04-15
]]></notes>
<cve>CVE-2021-1234</cve>
</suppress>
<!– 示例2:按文件名模式抑制 –>
<suppress>
<notes><![CDATA[
[抑制原因] 内部工具包不受此漏洞影响
[分析详情] 该漏洞需要特定配置触发,内部工具未使用该配置
[审核日期] 2024-01-15
[审核人] 李四
]]></notes>
<filePath regex="true">.*internal-tool-.*\\.jar</filePath>
<cve>CVE-2023-5678</cve>
</suppress>
<!– 示例3:按 CPE 抑制 –>
<suppress>
<notes><![CDATA[
[抑制原因] 仅用于开发测试,不部署到生产
[分析详情] H2 数据库仅用于单元测试,生产使用 MySQL
[审核日期] 2024-01-15
[审核人] 王五
]]></notes>
<cpe>cpe:/a:h2database:h2</cpe>
</suppress>
<!– 示例4:按包名和版本范围抑制 –>
<suppress>
<notes><![CDATA[
[抑制原因] 低风险,且升级不兼容
[分析详情] 该漏洞需要本地访问权限,无法远程利用
[审核日期] 2024-01-15
[审核人] 赵六
]]></notes>
<gav regex="true">^com\\.example:legacy-lib:1\\..*</gav>
<cve>CVE-2022-9999</cve>
</suppress>
<!– 示例5:临时抑制(带过期日期) –>
<suppress until="2024-03-01Z">
<notes><![CDATA[
[抑制原因] 临时抑制,等待官方补丁
[修复计划] 厂商预计 2024-02-15 发布补丁
[审核日期] 2024-01-15
[审核人] 钱七
]]></notes>
<cve>CVE-2024-0001</cve>
</suppress>
</suppressions>
抑制规则类型:
| <cve> | 按 CVE 编号抑制 | <cve>CVE-2021-44228</cve> |
| <cpe> | 按 CPE 标识抑制 | <cpe>cpe:/a:apache:log4j</cpe> |
| <filePath> | 按文件路径抑制 | <filePath regex="true">.*test.*</filePath> |
| <gav> | 按 Maven GAV 抑制 | <gav>com.example:lib:1.0</gav> |
| <sha1> | 按文件 SHA1 抑制 | <sha1>ABC123…</sha1> |
| <until> | 设置过期日期 | until="2024-12-31Z" |
抑制文件管理最佳实践:
4.3 报告解析与结果处理
JSON 报告结构解析:
{
"reportSchema": "1.1",
"scanInfo": {
"engineVersion": "12.1.0",
"dataSource": [
{"name": "NVD", "timestamp": "2024-01-15T00:00:00"}
]
},
"projectInfo": {
"name": "MyApplication",
"reportDate": "2024-01-15T10:30:00",
"credits": "OWASP Dependency-Check"
},
"dependencies": [
{
"fileName": "log4j-core-2.14.0.jar",
"filePath": "/path/to/log4j-core-2.14.0.jar",
"md5": "abc123…",
"sha1": "def456…",
"description": "Apache Log4j 2",
"license": "Apache-2.0",
"vulnerabilities": [
{
"name": "CVE-2021-44228",
"source": "NVD",
"severity": "CRITICAL",
"cvssv3": {
"baseScore": 10.0,
"attackVector": "NETWORK",
"attackComplexity": "LOW",
"privilegesRequired": "NONE",
"userInteraction": "NONE",
"scope": "CHANGED",
"confidentialityImpact": "HIGH",
"integrityImpact": "HIGH",
"availabilityImpact": "HIGH"
},
"description": "Apache Log4j2 远程代码执行漏洞",
"references": [
{
"source": "NVD",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2021-44228",
"name": "NVD"
}
],
"vulnerableSoftware": [
{
"software": "cpe:2.3:a:apache:log4j:*:*:*:*:*:*:*:*",
"versionStartIncluding": "2.0",
"versionEndExcluding": "2.15.0"
}
]
}
]
}
]
}
自动化处理脚本(Python):
#!/usr/bin/env python3
"""
Dependency-Check 报告解析器
用于 CI/CD 流水线中的自动化处理
"""
import json
import sys
from dataclasses import dataclass
from typing import List, Optional
from datetime import datetime
@dataclass
class Vulnerability:
cve: str
severity: str
cvss_score: float
description: str
fixed_version: Optional[str] = None
@dataclass
class Dependency:
name: str
version: str
file_path: str
vulnerabilities: List[Vulnerability]
class DependencyCheckParser:
def __init__(self, report_path: str):
with open(report_path, 'r', encoding='utf-8') as f:
self.report = json.load(f)
def get_summary(self) –> dict:
"""获取漏洞汇总统计"""
vulns = self._extract_vulnerabilities()
return {
'total_dependencies': len(self.report.get('dependencies', [])),
'vulnerable_dependencies': len([d for d in self.report.get('dependencies', [])
if d.get('vulnerabilities')]),
'total_vulnerabilities': len(vulns),
'critical': len([v for v in vulns if v.cvss_score >= 9.0]),
'high': len([v for v in vulns if 7.0 <= v.cvss_score < 9.0]),
'medium': len([v for v in vulns if 4.0 <= v.cvss_score < 7.0]),
'low': len([v for v in vulns if 0.1 <= v.cvss_score < 4.0]),
}
def get_vulnerabilities_by_severity(self, min_cvss: float = 0) –> List[Vulnerability]:
"""按严重程度获取漏洞列表"""
all_vulns = self._extract_vulnerabilities()
return [v for v in all_vulns if v.cvss_score >= min_cvss]
def generate_markdown_report(self) –> str:
"""生成 Markdown 格式的报告摘要"""
summary = self.get_summary()
report = f"""# Dependency-Check 安全报告
## 扫描概况
– **扫描时间**: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
– **总依赖数**: {summary['total_dependencies']}
– **存在漏洞的依赖**: {summary['vulnerable_dependencies']}
– **漏洞总数**: {summary['total_vulnerabilities']}
## 漏洞分布
| 严重程度 | 数量 | 说明 |
|———|——|——|
| 🔴 Critical | {summary['critical']} | CVSS 9.0-10.0 |
| 🟠 High | {summary['high']} | CVSS 7.0-8.9 |
| 🟡 Medium | {summary['medium']} | CVSS 4.0-6.9 |
| 🟢 Low | {summary['low']} | CVSS 0.1-3.9 |
## 高危漏洞详情
"""
critical_high = self.get_vulnerabilities_by_severity(7.0)
for vuln in critical_high[:10]: # 只显示前10个
report += f"""### {vuln.cve} ({vuln.severity})
– **CVSS Score**: {vuln.cvss_score}
– **影响组件**: {vuln.name}
– **漏洞描述**: {vuln.description[:200]}…
"""
return report
def _extract_vulnerabilities(self) –> List[Vulnerability]:
"""提取所有漏洞信息"""
vulnerabilities = []
for dep in self.report.get('dependencies', []):
for vuln_data in dep.get('vulnerabilities', []):
cvssv3 = vuln_data.get('cvssv3', {})
vuln = Vulnerability(
cve=vuln_data.get('name', 'Unknown'),
severity=vuln_data.get('severity', 'Unknown'),
cvss_score=cvssv3.get('baseScore', 0),
description=vuln_data.get('description', 'No description'),
fixed_version=self._extract_fixed_version(vuln_data)
)
vulnerabilities.append(vuln)
return vulnerabilities
def _extract_fixed_version(self, vuln_data: dict) –> Optional[str]:
"""提取修复版本信息"""
# 从漏洞数据中解析建议的修复版本
for ref in vuln_data.get('references', []):
if 'upgrade' in ref.get('name', '').lower():
return ref.get('name')
return None
def main():
if len(sys.argv) < 2:
print("Usage: python parse_report.py <report.json>")
sys.exit(1)
parser = DependencyCheckParser(sys.argv[1])
summary = parser.get_summary()
print(json.dumps(summary, indent=2))
# 如果有严重漏洞,返回非0退出码
if summary['critical'] > 0:
sys.exit(1)
if __name__ == '__main__':
main()
4.4 性能优化
数据库缓存优化:
# 使用共享数据目录(Docker)
docker run –rm \\
-v /shared/dependency-check-data:/usr/share/dependency-check/data:rw \\
...
# 定期更新(cron 任务)
0 2 * * * /opt/dependency-check/bin/dependency-check.sh –updateonly –nvdApiKey xxx
并行扫描优化:
// Jenkins Pipeline 中并行执行不同类型的扫描
pipeline {
agent any
stages {
stage('Security Scans') {
parallel {
stage('Dependency-Check') {
steps {
dependencyCheck …
}
}
stage('SonarQube') {
steps {
withSonarQubeEnv('SonarQube') {
sh 'mvn sonar:sonar'
}
}
}
stage('Container Scan') {
steps {
sh 'trivy image myapp:latest'
}
}
}
}
}
}
增量扫描(实验性功能):
<plugin>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId>
<configuration>
<!– 仅扫描变更的依赖(需要配合 Maven 的增量构建) –>
<skipArtifactType>pom</skipArtifactType>
</configuration>
</plugin>
第五部分:完整项目案例
5.1 项目背景与架构
项目名称: E-Shop 电商平台
技术栈:
- 后端:Spring Boot 3.2 + Java 17 + Maven
- 前端:Vue 3 + TypeScript + Vite
- 数据库:MySQL 8.0 + Redis
- 部署:Docker + Kubernetes
- CI/CD:Jenkins
项目结构:
e-shop/
├── backend/
│ ├── pom.xml # Maven 配置
│ ├── dependency-check-suppressions.xml
│ └── src/…
├── frontend/
│ ├── package.json # npm 配置
│ └── src/…
├── docker-compose.yml
├── Jenkinsfile
└── README.md
5.2 后端 Maven 配置
pom.xml 完整配置:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.0</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>e-shop-backend</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<properties>
<java.version>17</java.version>
<nvd.api.key>${env.NVD_API_KEY}</nvd.api.key>
</properties>
<dependencies>
<!– Spring Boot Starters –>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!– Database –>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
<!– JWT –>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.12.3</version>
</dependency>
<!– Test –>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<!– Spring Boot Plugin –>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<!– OWASP Dependency-Check Plugin –>
<plugin>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId>
<version>12.1.0</version>
<configuration>
<nvdApiKey>${nvd.api.key}</nvdApiKey>
<failBuildOnCVSS>7</failBuildOnCVSS>
<format>ALL</format>
<outputDirectory>${project.build.directory}/dependency-check</outputDirectory>
<suppressionFiles>
<suppressionFile>dependency-check-suppressions.xml</suppressionFile>
</suppressionFiles>
<skipTestScope>true</skipTestScope>
<enableExperimental>true</enableExperimental>
</configuration>
<executions>
<execution>
<id>dependency-check</id>
<phase>verify</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
<!– SonarQube Plugin –>
<plugin>
<groupId>org.sonarsource.scanner.maven</groupId>
<artifactId>sonar-maven-plugin</artifactId>
<version>3.10.0.2594</version>
</plugin>
</plugins>
</build>
<profiles>
<!– 开发环境:不阻断构建 –>
<profile>
<id>dev</id>
<properties>
<dependency-check.failBuildOnCVSS>11</dependency-check.failBuildOnCVSS>
</properties>
</profile>
<!– 生产环境:严格检查 –>
<profile>
<id>prod</id>
<properties>
<dependency-check.failBuildOnCVSS>5</dependency-check.failBuildOnCVSS>
</properties>
</profile>
</profiles>
</project>
抑制文件(dependency-check-suppressions.xml):
<?xml version="1.0" encoding="UTF-8"?>
<suppressions xmlns="https://jeremylong.github.io/DependencyCheck/dependency-suppression.1.3.xsd">
<!– 测试依赖的漏洞(不影响生产) –>
<suppress>
<notes><![CDATA[
仅用于单元测试的 H2 数据库,生产环境使用 MySQL
]]></notes>
<gav regex="true">^com\\.h2database:h2:.*</gav>
<cpe>cpe:/a:h2database:h2</cpe>
</suppress>
</suppressions>
5.3 前端 npm 配置
前端扫描脚本配置:
// frontend/package.json
{
"name": "e-shop-frontend",
"version": "1.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vue-tsc && vite build",
"preview": "vite preview",
"test": "vitest",
"lint": "eslint . –ext .vue,.ts,.tsx –fix",
"security:check": "npm audit && npm run owasp:check",
"security:check-ci": "npm audit –audit-level=moderate && npm run owasp:check-ci",
"owasp:check": "dependency-check –project E-Shop-Frontend –scan package.json –scan package-lock.json –format HTML –format JSON –out reports –enableExperimental",
"owasp:check-ci": "dependency-check –project E-Shop-Frontend –scan package.json –scan package-lock.json –format JSON –failOnCVSS 7 –out reports –enableExperimental",
"precommit": "npm run lint && npm run security:check-ci"
},
"dependencies": {
"vue": "^3.3.8",
"vue-router": "^4.2.5",
"pinia": "^2.1.7",
"axios": "^1.6.2"
},
"devDependencies": {
"@vitejs/plugin-vue": "^4.5.0",
"typescript": "^5.2.2",
"vite": "^5.0.0",
"vue-tsc": "^1.8.22",
"vitest": "^0.34.6",
"eslint": "^8.54.0",
"@vue/eslint-config-typescript": "^12.0.0"
}
}
Git 预提交钩子(frontend/.husky/pre-commit):
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
cd frontend
# 运行 lint
npm run lint
if [ $? -ne 0 ]; then
echo "❌ 代码检查失败,请修复后重试"
exit 1
fi
# 运行依赖扫描(快速模式)
npm audit –audit-level=moderate
if [ $? -ne 0 ]; then
echo "❌ 发现 npm 依赖漏洞"
exit 1
fi
echo "✅ 预提交检查通过"
5.4 Jenkins Pipeline 完整配置
Jenkinsfile:
pipeline {
agent any
environment {
NVD_API_KEY = credentials('nvd-api-key')
SONAR_TOKEN = credentials('sonar-token')
DOCKER_REGISTRY = 'registry.company.com'
APP_NAME = 'e-shop'
}
tools {
maven 'maven-3.9'
nodejs 'nodejs-20'
dependencyCheck 'dependency-check'
}
options {
buildDiscarder(logRotator(numToKeepStr: '10'))
timestamps()
timeout(time: 30, unit: 'MINUTES')
}
stages {
stage('Checkout') {
steps {
checkout scm
sh 'git log –oneline -5'
}
}
stage('Backend Build & Test') {
steps {
dir('backend') {
sh 'mvn clean compile test'
}
}
post {
always {
dir('backend') {
junit 'target/surefire-reports/*.xml'
}
}
}
}
stage('Frontend Build & Test') {
steps {
dir('frontend') {
sh 'npm ci'
sh 'npm run build'
sh 'npm test'
}
}
}
stage('Security Scans') {
parallel {
stage('Backend Dependency-Check') {
steps {
dir('backend') {
// 使用 Maven 插件运行
sh 'mvn dependency-check:check'
}
}
post {
always {
dir('backend') {
dependencyCheckPublisher pattern: 'target/dependency-check-report.xml'
archiveArtifacts artifacts: 'target/dependency-check-report.*', allowEmptyArchive: true
}
}
}
}
stage('Frontend Dependency-Check') {
steps {
dir('frontend') {
dependencyCheck additionalArguments: """
–project "E-Shop-Frontend"
–scan package.json
–scan package-lock.json
–format HTML
–format XML
–format JSON
–failOnCVSS 7
–nvdApiKey ${NVD_API_KEY}
–out reports
–enableExperimental
""",
odcInstallation: 'dependency-check'
}
}
post {
always {
dir('frontend') {
dependencyCheckPublisher pattern: 'reports/dependency-check-report.xml'
archiveArtifacts artifacts: 'reports/dependency-check-report.*', allowEmptyArchive: true
}
}
}
}
stage('SonarQube Analysis') {
steps {
dir('backend') {
withSonarQubeEnv('SonarQube') {
sh """
mvn sonar:sonar \\
-Dsonar.projectKey=e-shop-backend \\
-Dsonar.projectName="E-Shop Backend" \\
-Dsonar.dependencyCheck.reportPath=target/dependency-check-report.xml
"""
}
}
}
}
stage('npm Audit') {
steps {
dir('frontend') {
sh 'npm audit –audit-level=moderate'
}
}
}
}
}
stage('Security Gate') {
steps {
script {
def backendReport = readJSON file: 'backend/target/dependency-check-report.json'
def frontendReport = readJSON file: 'frontend/reports/dependency-check-report.json'
def backendVulns = backendReport.dependencies.collectMany { it.vulnerabilities ?: [] }
def frontendVulns = frontendReport.dependencies.collectMany { it.vulnerabilities ?: [] }
def allVulns = backendVulns + frontendVulns
def critical = allVulns.count { it.cvssv3?.baseScore >= 9.0 }
def high = allVulns.count { it.cvssv3?.baseScore >= 7.0 && it.cvssv3?.baseScore < 9.0 }
def medium = allVulns.count { it.cvssv3?.baseScore >= 4.0 && it.cvssv3?.baseScore < 7.0 }
echo "🔒 依赖扫描结果汇总:"
echo " 严重: ${critical}"
echo " 高危: ${high}"
echo " 中危: ${medium}"
// 安全门禁策略
if (critical > 0) {
error "❌ 发现 ${critical} 个严重漏洞,阻塞发布!请立即修复。"
}
if (high > 3) {
input message: "发现 ${high} 个高危漏洞,是否继续部署?",
ok: '确认部署',
submitter: 'security-team,devops-team'
}
if (medium > 20) {
unstable "⚠️ 中危漏洞数量较多(${medium}个),建议安排修复计划"
}
echo "✅ 安全门禁通过"
}
}
}
stage('Build Docker Images') {
steps {
script {
def version = sh(script: 'git describe –tags –always', returnStdout: true).trim()
env.IMAGE_TAG = version
// Build backend image
dir('backend') {
sh """
docker build \\
-t ${DOCKER_REGISTRY}/${APP_NAME}-backend:${version} \\
-t ${DOCKER_REGISTRY}/${APP_NAME}-backend:latest \\
.
"""
}
// Build frontend image
dir('frontend') {
sh """
docker build \\
-t ${DOCKER_REGISTRY}/${APP_NAME}-frontend:${version} \\
-t ${DOCKER_REGISTRY}/${APP_NAME}-frontend:latest \\
.
"""
}
}
}
}
stage('Container Security Scan') {
steps {
script {
// Scan backend image
sh """
trivy image \\
–severity HIGH,CRITICAL \\
–exit-code 1 \\
${DOCKER_REGISTRY}/${APP_NAME}-backend:${IMAGE_TAG}
"""
// Scan frontend image
sh """
trivy image \\
–severity HIGH,CRITICAL \\
–exit-code 1 \\
${DOCKER_REGISTRY}/${APP_NAME}-frontend:${IMAGE_TAG}
"""
}
}
}
stage('Push Images') {
when {
anyOf {
branch 'main'
branch 'release/*'
}
}
steps {
script {
sh """
docker push ${DOCKER_REGISTRY}/${APP_NAME}-backend:${IMAGE_TAG}
docker push ${DOCKER_REGISTRY}/${APP_NAME}-backend:latest
docker push ${DOCKER_REGISTRY}/${APP_NAME}-frontend:${IMAGE_TAG}
docker push ${DOCKER_REGISTRY}/${APP_NAME}-frontend:latest
"""
}
}
}
stage('Deploy to Test') {
when {
branch 'develop'
}
steps {
sh '''
kubectl set image deployment/e-shop-backend \\
backend=${DOCKER_REGISTRY}/${APP_NAME}-backend:${IMAGE_TAG} \\
-n test
kubectl rollout status deployment/e-shop-backend -n test
'''
}
}
}
post {
always {
// 生成安全报告汇总
script {
def summary = """
## 构建报告
– **项目**: ${env.JOB_NAME}
– **构建号**: ${env.BUILD_NUMBER}
– **分支**: ${env.BRANCH_NAME}
– **提交**: ${env.GIT_COMMIT?.take(8)}
### 构建结果: ${currentBuild.currentResult}
详细报告请查看:${env.BUILD_URL}
"""
echo summary
}
cleanWs()
}
failure {
emailext (
subject: "❌ 构建失败: ${env.JOB_NAME} #${env.BUILD_NUMBER}",
body: """构建失败,可能发现安全问题。
项目: ${env.JOB_NAME}
分支: ${env.BRANCH_NAME}
构建号: ${env.BUILD_NUMBER}
查看详情: ${env.BUILD_URL}
请检查 Dependency-Check 报告。""",
to: "${env.CHANGE_AUTHOR_EMAIL ?: 'dev-team@company.com'}",
recipientProviders: [developers(), requestor()]
)
}
unstable {
emailext (
subject: "⚠️ 构建不稳定: ${env.JOB_NAME} #${env.BUILD_NUMBER}",
body: """发现安全问题,需要关注。
查看详情: ${env.BUILD_URL}""",
to: "security-team@company.com"
)
}
}
}
5.5 生产级 Pipeline 实践(多模块 + 条件执行)
以下是一个实际生产环境中使用的 Jenkins Pipeline,适用于多模块 Maven 项目,并根据不同环境(DEV/TEST/PROD)执行不同的阶段。
特点:
- 参数化构建:动态选择环境、服务器和分支
- 条件执行:DEV 环境执行代码质量和依赖扫描,TEST/PROD 执行编译部署
- 多模块支持:使用 aggregate 生成统一报告
- 离线优化:跳过数据库更新,避免网络问题
完整 Pipeline:
// 流水线属性配置
properties([
// 管道速度/耐久性优化
durabilityHint('PERFORMANCE_OPTIMIZED'),
// 保留已完成构建的储藏
preserveStashes(),
// 配置联动选框参数
parameters([
activeChoice(
choiceType: 'PT_SINGLE_SELECT',
description: '选择部署环境',
filterLength: 1,
filterable: false,
name: 'Environment',
script: scriptlerScript(
isSandboxed: true,
scriptlerBuilder: [
builderId: '1726884996564_17',
scriptId: 'Environments.groovy'
]
)
),
reactiveChoice(
choiceType: 'PT_CHECKBOX',
description: '选择需要构建的应用',
filterLength: 1,
filterable: true,
name: 'Servers',
referencedParameters: 'Environment',
script: scriptlerScript(
isSandboxed: true,
scriptlerBuilder: [
builderId: '1726884996566_18',
scriptId: 'BackendApps.groovy'
]
)
)
])
])
// 动态 JDK 版本选择
def jdkVersion = params.Environment?.contains('DEV') ? 'jdk-17' : 'jdk-11'
pipeline {
agent any
tools {
maven 'local-mvn'
jdk jdkVersion
}
options {
buildDiscarder(logRotator(numToKeepStr: '10'))
}
parameters {
string(
defaultValue: 'http://gitlab.example.com/project/backend.git',
description: '代码仓库地址',
name: 'Gitlab_Registry_URL'
)
gitParameter(
branch: '',
branchFilter: '.*',
defaultValue: 'develop',
description: '选择代码分支',
name: 'branch',
type: 'GitParameterDefinition'
)
}
environment {
commitLog = ''
commit_author = ''
SonarQube_URL = 'http://sonarqube.example.com:9000'
SonarQube_Secret = credentials('sonar-token')
ProjectName = "${env.JOB_NAME}"
scannerHome = tool 'SonarQube_Scanner_4.8'
build_time = ''
DOCKER_REPOSITORY = 'registry.example.com/project'
commit_counters = ''
}
stages {
stage('代码拉取') {
steps {
echo "当前使用的 JDK 版本: ${jdkVersion}"
checkout scmGit(
branches: [[name: '${branch}']],
extensions: [],
userRemoteConfigs: [[
credentialsId: 'gitlab-credentials',
url: '${Gitlab_Registry_URL}'
]]
)
script {
// 获取代码提交信息
commitLog = sh(
script: 'git log –oneline -n 1',
returnStdout: true
).trim()
commit_author = sh(
script: 'git log -n 1 –pretty=format:"%an"',
returnStdout: true
).trim()
commit_counters = sh(
script: 'git log –oneline | wc -l',
returnStdout: true
).trim()
build_time = sh(
script: 'date +%Y%m%d%H%M',
returnStdout: true
).trim()
echo "提交信息: ${commitLog}"
echo "提交人: ${commit_author}"
echo "提交次数: ${commit_counters}"
}
}
}
// DEV 环境执行代码质量检查
stage('SonarQube Analysis') {
when {
expression {
return params.Environment.contains('DEV')
}
}
steps {
echo '执行 SonarQube 代码质量分析'
script {
def sonarProperties = [
"sonar.projectKey=${ProjectName}",
"sonar.host.url=${SonarQube_URL}",
"sonar.login=${SonarQube_Secret}"
]
withSonarQubeEnv('SonarQube') {
sh "mvn clean install sonar:sonar -D${sonarProperties.join(' -D')} -DskipTests -Ddockerfile.skip=true"
}
// 等待质量门禁结果
timeout(time: 5, unit: 'MINUTES') {
waitForQualityGate abortPipeline: false
}
}
}
}
// DEV 环境执行依赖安全检查
stage('Dependency-Check Analysis') {
when {
expression {
return params.Environment.contains('DEV')
}
}
steps {
echo '执行 OWASP Dependency-Check 依赖安全扫描'
script {
// 多模块项目使用 aggregate 生成汇总报告
// skipAllUpdates=true: 跳过数据库更新(适用于离线环境)
// retirejs.skip=true: 跳过 RetireJS 分析器
// assemblyAnalyzerEnabled=false: 禁用 .NET Assembly 分析器
sh """mvn org.owasp:dependency-check-maven:12.1.0:aggregate \\
-Ddependency-check.reportFormat=ALL \\
-Dformats=XML,HTML \\
-Ddependency-check.skipAllUpdates=true \\
-Ddependency-check.retirejs.skip=true \\
-DassemblyAnalyzerEnabled=false \\
-Ddependency-check.outputDirectory=target"""
}
}
}
// 发布依赖扫描结果到 Jenkins
stage('Publish Dependency-Check Results') {
when {
expression {
return params.Environment.contains('DEV')
}
}
steps {
echo '发布依赖安全检查结果'
script {
// 发布 HTML 报告到 Jenkins 侧边栏
publishHTML([
allowMissing: true,
alwaysLinkToLastBuild: true,
keepAll: true,
reportDir: 'target',
reportFiles: 'dependency-check-report.html',
reportName: 'Dependency-Check Report'
])
// 生成漏洞趋势图
dependencyCheckPublisher pattern: 'target/dependency-check-report.xml'
}
}
}
// TEST/PROD 环境执行编译
stage('编译') {
when {
anyOf {
expression { return params.Environment.contains('TEST') }
expression { return params.Environment.contains('PROD') }
}
}
steps {
echo '编译打包'
sh "mvn clean install -Dmaven.test.skip=true -Ddockerfile.skip=true"
}
}
// TEST/PROD 环境构建并推送镜像
stage('打包镜像并推送仓库') {
when {
anyOf {
expression { return params.Environment.contains('TEST') }
expression { return params.Environment.contains('PROD') }
}
}
steps {
echo '构建 Docker 镜像'
script {
for (server in params.Servers.tokenize(',')) {
// 构建镜像
sh "docker build -t ${DOCKER_REPOSITORY}/${server}:${build_time}_${commit_counters} ${server} –no-cache"
// 推送镜像到仓库
sh "docker push ${DOCKER_REPOSITORY}/${server}:${build_time}_${commit_counters}"
// 清理本地镜像
sh "docker rmi ${DOCKER_REPOSITORY}/${server}:${build_time}_${commit_counters}"
}
}
}
}
// 测试环境部署
stage('测试环境部署') {
when {
expression { return params.Environment.contains('TEST') }
}
steps {
echo '部署到测试环境'
script {
for (server in params.Servers.tokenize(',')) {
sh "scp ${server}/target/*.jar user@test-server:/home/app/${server}/"
sh "ssh user@test-server bash -l -c /home/app/${server}/restart.sh"
}
}
}
}
// 生产环境部署
stage('生产环境部署') {
when {
expression { return params.Environment.contains('PROD') }
}
steps {
echo '部署到生产环境'
script {
for (server in params.Servers.tokenize(',')) {
sh "scp ${server}/target/*.jar user@prod-server:/home/app/${server}/"
sh "ssh user@prod-server bash -l -c /home/app/${server}/restart.sh"
}
}
}
}
}
post {
always {
cleanWs()
}
failure {
emailext(
subject: "❌ 构建失败: ${env.JOB_NAME} #${env.BUILD_NUMBER}",
body: """构建失败!
项目: ${env.JOB_NAME}
分支: ${env.BRANCH_NAME}
环境: ${params.Environment}
提交人: ${commit_author}
提交信息: ${commitLog}
查看详情: ${env.BUILD_URL}""",
to: "${commit_author}@company.com"
)
}
}
}
关键配置说明:
| aggregate | 多模块项目生成汇总报告 | 多模块 Maven 项目 |
| skipAllUpdates=true | 跳过 NVD 数据库更新 | 内网/离线环境 |
| retirejs.skip=true | 跳过 JavaScript 分析器 | 纯后端项目 |
| assemblyAnalyzerEnabled=false | 禁用 .NET 分析器 | 无 .NET 依赖的项目 |
| publishHTML | 发布 HTML 报告到 Jenkins UI | 需要可视化报告 |
| dependencyCheckPublisher | 生成漏洞趋势图 | 需要历史趋势对比 |
5.6 前端项目 Pipeline 实践(Node.js + CLI 工具)
💡 说明:本节提供完整的生产级 Pipeline,展示前端项目的依赖扫描实践。3.3 节介绍了基础的 Jenkins 集成方案,5.4 节展示了后端 Maven 项目的完整 Pipeline。
以下是一个前端 Vue 项目的 Jenkins Pipeline 示例,使用 Dependency-Check CLI 工具进行依赖安全扫描。
特点:
- 前端项目(Vue.js + npm)构建
- 使用 CLI 工具(dependency-check.sh)而非 Maven 插件
- 条件执行:DEV 环境执行代码质量和依赖扫描
- 跳过可选分析器避免错误(Yarn Audit、RetireJS)
- 使用 –noupdate 禁用数据库更新,加速构建
完整 Pipeline:
pipeline {
agent any
options {
buildDiscarder(logRotator(numToKeepStr: '10'))
}
tools {
jdk 'jdk-17'
nodejs 'nodejs-14.17.6'
}
parameters {
string(
defaultValue: 'http://gitlab.example.com/project/frontend.git',
description: '代码仓库地址',
name: 'Gitlab_Registry_URL'
)
gitParameter(
branch: '',
branchFilter: '.*',
defaultValue: 'release-dev',
description: '选择代码分支',
name: 'branch',
type: 'GitParameterDefinition'
)
choice(
name: 'Environment',
choices: ['DEV', 'TEST', 'PROD'],
description: '选择部署环境'
)
}
environment {
commitLog = ''
commit_author = ''
ProjectName = "${env.JOB_NAME}"
scannerHome = tool 'SonarQube_Scanner_4.8'
dependencyCheckHome = tool 'dependency-check-12.1.0'
SonarQube_URL = 'http://sonarqube.example.com:9000'
SonarQube_Secret = credentials('sonar-token')
}
stages {
stage('代码拉取') {
steps {
echo '拉取 Git 代码'
checkout scmGit(
branches: [[name: '${branch}']],
extensions: [],
userRemoteConfigs: [[
credentialsId: 'gitlab-credentials',
url: '${Gitlab_Registry_URL}'
]]
)
script {
commitLog = sh(
script: 'git log –oneline -n 1',
returnStdout: true
).trim()
commit_author = sh(
script: 'git log -n 1 –pretty=format:"%an"',
returnStdout: true
).trim()
echo "提交信息: ${commitLog}"
echo "提交人: ${commit_author}"
}
}
}
// DEV 环境执行 SonarQube 代码质量检查
stage('SonarQube Analysis') {
when {
expression {
return params.Environment.contains('DEV')
}
}
steps {
echo '执行 SonarQube 代码质量分析'
script {
withSonarQubeEnv('SonarQube') {
sh '''
${scannerHome}/bin/sonar-scanner \\
-Dsonar.projectKey=${ProjectName} \\
-Dsonar.sources=. \\
-Dsonar.host.url=${SonarQube_URL} \\
-Dsonar.login=${SonarQube_Secret}
'''
}
// 等待质量门禁
timeout(time: 3, unit: 'MINUTES') {
waitForQualityGate abortPipeline: false
}
}
}
}
// DEV 环境执行 Dependency-Check 依赖扫描
stage('Dependency-Check Analysis') {
when {
expression {
return params.Environment.contains('DEV')
}
}
steps {
echo '执行依赖安全检查'
script {
// 安装 npm 依赖
try {
sh '''
npm cache clean –force || echo "警告:npm cache clean 失败,继续执行"
npm install –unsafe-perm || {
echo "错误:npm install 失败"
exit 1
}
'''
} catch (Exception e) {
error "依赖安装失败:${e.getMessage()}"
}
// 确保输出目录存在
sh 'mkdir -p target || { echo "错误:创建目标目录失败"; exit 1; }'
// 使用 CLI 工具执行扫描
// –noupdate: 禁用数据库更新,加速构建
// –disableYarnAudit: 禁用 Yarn Audit(避免报错)
// –disableRetireJS: 禁用 RetireJS(避免报错)
// –disableAssembly: 禁用 Assembly 分析器
try {
sh """
${dependencyCheckHome}/bin/dependency-check.sh \\
–project "${ProjectName}" \\
–scan . \\
–out target \\
–format HTML \\
–format XML \\
–disableAssembly \\
–noupdate \\
–disableYarnAudit \\
–disableRetireJS
"""
} catch (Exception e) {
error "依赖扫描失败:${e.getMessage()}"
}
}
}
}
// 发布扫描结果
stage('Publish Dependency-Check Results') {
when {
expression {
return params.Environment.contains('DEV')
}
}
steps {
echo '发布依赖安全检查结果'
script {
// 发布 HTML 报告
publishHTML([
allowMissing: true,
alwaysLinkToLastBuild: true,
keepAll: true,
reportDir: 'target',
reportFiles: 'dependency-check-report.html',
reportName: 'Dependency-Check Report'
])
// 生成漏洞趋势图
dependencyCheckPublisher pattern: 'target/dependency-check-report.xml'
}
}
}
// TEST/PROD 环境编译构建
stage('编译构建') {
when {
anyOf {
expression { return params.Environment.contains('TEST') }
expression { return params.Environment.contains('PROD') }
}
}
steps {
script {
try {
sh '''
npm cache clean –force || echo "警告:npm cache clean 失败,继续执行"
npm install –unsafe-perm || {
echo "错误:npm install 失败"
exit 1
}
npm run build:test || {
echo "错误:构建失败"
exit 1
}
'''
} catch (Exception e) {
error "编译构建失败:${e.getMessage()}"
}
}
}
}
// 测试环境部署
stage('测试环境部署') {
when {
expression { return params.Environment.contains('TEST') }
}
steps {
script {
try {
sh '''
# 检查构建产物是否存在
if [ ! -d "dist" ]; then
echo "错误:构建产物目录 dist 不存在"
exit 1
fi
# 备份旧版本
ssh user@test-server "mv /home/app/front/acm /home/app/front/acm-`date +%Y%m%d%H%M`" || {
echo "警告:备份旧版本失败,可能首次部署"
}
# 部署新版本
rm -rf acm || { echo "错误:清理临时目录失败"; exit 1; }
mv dist acm || { echo "错误:重命名构建产物失败"; exit 1; }
scp -r acm user@test-server:/home/app/front/acm || {
echo "错误:上传到测试服务器失败"
exit 1
}
echo "测试环境部署成功"
'''
} catch (Exception e) {
error "测试环境部署失败:${e.getMessage()}"
}
}
}
}
// 生产环境部署
stage('生产环境部署') {
when {
expression { return params.Environment.contains('PROD') }
}
steps {
script {
try {
sh '''
# 检查构建产物是否存在
if [ ! -d "dist" ]; then
echo "错误:构建产物目录 dist 不存在"
exit 1
fi
# 备份旧版本(生产环境必须成功)
ssh user@prod-server "mv /home/app/front/acm /home/app/front/acm-`date +%Y%m%d%H%M`" || {
echo "错误:备份生产环境旧版本失败"
exit 1
}
# 部署新版本
rm -rf acm || { echo "错误:清理临时目录失败"; exit 1; }
mv dist acm || { echo "错误:重命名构建产物失败"; exit 1; }
scp -r acm user@prod-server:/home/app/front/acm || {
echo "错误:上传到生产服务器失败"
exit 1
}
echo "生产环境部署成功"
'''
} catch (Exception e) {
error "生产环境部署失败:${e.getMessage()}"
}
}
}
}
}
}
关键配置说明:
| dependency-check.sh | CLI 工具路径 | Jenkins 全局工具配置 |
| –scan . | 扫描当前目录 | 前端项目根目录 |
| –noupdate | 跳过 NVD 数据库更新 | 加速构建,离线环境 |
| –disableYarnAudit | 禁用 Yarn Audit | 避免 npm 项目报错 |
| –disableRetireJS | 禁用 RetireJS | 避免网络超时 |
| –disableAssembly | 禁用 Assembly 分析器 | 前端项目不需要 |
| publishHTML | 发布 HTML 报告 | 可视化查看 |
| dependencyCheckPublisher | 生成趋势图 | Jenkins 漏洞统计 |
5.7 NVD 数据库定时更新 Job
在实际生产环境中,为了避免每次构建都下载漏洞数据库(耗时且不稳定),建议创建一个独立的 Jenkins Job 专门用于定期更新 NVD 数据库。业务项目的 Pipeline 则配置为跳过更新(–noupdate 或 skipAllUpdates=true),直接使用本地缓存的数据。
特点:
- 定时执行:每天凌晨自动更新
- 独立运行:不影响业务构建
- 与业务项目使用相同版本的插件
完整 Pipeline:
// 用于定期更新 NVD 数据库的独立 Jenkins Job
// 建议配置为定时任务(如每天凌晨)
properties([
// 管道速度/耐久性覆盖
durabilityHint('PERFORMANCE_OPTIMIZED'),
// 配置定时任务,每天凌晨2点执行
pipelineTriggers([cron('0 2 * * *')])
])
pipeline {
agent any
// 使用与主项目相同的JDK版本
tools {
maven 'local-mvn'
jdk 'jdk-17'
}
stages {
stage('Update NVD Database') {
steps {
echo '开始更新 NVD 数据库…'
script {
try {
// 仅执行数据库更新操作,不进行扫描
// 使用与主项目相同版本的dependency-check插件
sh """
mvn org.owasp:dependency-check-maven:12.1.0:update-only || {
echo "错误:NVD 数据库更新失败"
echo "请检查:"
echo "1. 网络连接是否正常"
echo "2. NVD API Key 是否有效"
echo "3. 磁盘空间是否充足"
exit 1
}
"""
echo "NVD 数据库更新成功"
} catch (Exception e) {
error "NVD 数据库更新失败:${e.getMessage()}"
}
}
}
}
}
post {
success {
echo 'NVD 数据库更新成功'
}
failure {
echo 'NVD 数据库更新失败,请检查日志'
}
}
}
配置说明:
| pipelineTriggers | 定时触发器 | cron('0 2 * * *') 每天凌晨2点 |
| update-only | 仅更新数据库,不扫描 | 适用于定时任务 |
| 插件版本 | 与业务项目保持一致 | 12.1.0 |
使用方式:
5.8 安全门禁与质量门禁
门禁策略总结:
| 严重漏洞 (CVSS 9.0+) | >= 1 | – | 立即阻断,必须修复 |
| 高危漏洞 (CVSS 7.0-8.9) | > 3 | 1-3 | 超过3个需安全团队审批 |
| 中危漏洞 (CVSS 4.0-6.9) | – | > 20 | 记录技术债务,计划修复 |
| npm audit | moderate+ | – | 阻断构建 |
| 容器扫描 | HIGH+ | – | 阻断构建 |
5.9 漏洞修复流程
发现漏洞后的处理流程:
发现漏洞
↓
评估影响
├─ 确认是否适用(查看漏洞详情)
├─ 评估修复难度
└─ 确定优先级
↓
选择修复方案
├─ 升级依赖版本(首选)
├─ 更换依赖(不兼容时)
├─ 缓解措施(临时)
└─ 接受风险(需审批)
↓
实施修复
↓
验证修复
├─ 重新运行依赖扫描
├─ 功能回归测试
└─ 验证抑制文件(如适用)
↓
关闭漏洞
修复示例:
# 1. 发现 log4j-core 存在漏洞
# mvn dependency-check:check 报告 CVE-2021-44228
# 2. 查看当前版本
echo "检查 log4j 依赖…"
mvn dependency:tree | grep log4j || {
echo "错误:未找到 log4j 依赖"
exit 1
}
# 3. 查看可用修复版本(访问 Maven Central)
# https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core
# 4. 更新 pom.xml 中的版本
# <log4j.version>2.17.1</log4j.version>
# 5. 验证修复
echo "验证修复…"
mvn clean compile || {
echo "错误:编译失败,请检查版本兼容性"
exit 1
}
mvn dependency-check:check || {
echo "错误:依赖扫描失败,漏洞可能未修复"
exit 1
}
echo "✅ 修复成功!漏洞已解决"
# 6. 提交修复
git add pom.xml || {
echo "错误:git add 失败"
exit 1
}
git commit -m "security: 升级 log4j 到 2.17.1 修复 CVE-2021-44228" || {
echo "错误:git commit 失败"
exit 1
}
git push || {
echo "错误:git push 失败,请检查远程仓库配置"
exit 1
}
echo "✅ 修复已提交并推送到远程仓库"
第六部分:DevSecOps 扩展
6.1 与 DAST、SAST 工具的配合
完整 DevSecOps 安全工具链:
开发阶段 构建阶段 测试阶段 部署阶段 运行阶段
│ │ │ │ │
▼ ▼ ▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
│ IDE插件 │ │ SCA │ │ SAST │ │ 镜像扫描 │ │ RASP │
│SonarLint│ → │Dependency│ → │SonarQube│ → │ Trivy │ → │ WAF │
│ ESLint │ │ Check │ │Checkmarx│ │ Snyk │ │监控告警 │
└─────────┘ └─────────┘ └─────────┘ └─────────┘ └─────────┘
│ │ │
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐
│ npm │ │ DAST │ │ IaC扫描 │
│ audit │ │ OWASP │ │Checkov │
│ │ │ ZAP │ │ │
└─────────┘ └─────────┘ └─────────┘
各阶段工具配置:
| 开发 | IDE 插件 | SonarLint, ESLint | IDE 自动检查 |
| 构建 | SCA | Dependency-Check | Maven/Gradle 插件 |
| 构建 | SAST | SonarQube | Maven 插件 + Jenkins |
| 测试 | DAST | OWASP ZAP | Jenkins Pipeline |
| 部署 | 镜像扫描 | Trivy | Jenkins Pipeline |
| 部署 | IaC 扫描 | Checkov | Jenkins Pipeline |
| 运行 | 运行时防护 | RASP, WAF | 基础设施部署 |
6.2 容器安全扫描(Trivy)集成
Trivy 安装与使用:
# 安装 Trivy
# macOS
brew install trivy
# Linux
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh
# Docker
docker pull aquasec/trivy
扫描镜像:
# 基础扫描
trivy image myapp:latest
# 只显示高危漏洞
trivy image –severity HIGH,CRITICAL myapp:latest
# 生成报告
trivy image –format sarif –output trivy-report.sarif myapp:latest
# 扫描 Dockerfile
trivy config Dockerfile
Jenkins Pipeline 集成:
stage('Container Security Scan') {
steps {
script {
// 安装 Trivy(如果未安装)
sh '''
if ! command -v trivy &> /dev/null; then
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh
fi
'''
// 扫描镜像
sh """
trivy image \\
–severity HIGH,CRITICAL \\
–format json \\
–output trivy-report.json \\
–exit-code 1 \\
${DOCKER_IMAGE}:${VERSION}
"""
}
}
post {
always {
// 归档报告
archiveArtifacts artifacts: 'trivy-report.json', allowEmptyArchive: true
}
}
}
6.3 安全运营与持续改进
安全度量指标:
| 依赖扫描覆盖率 | 参与扫描的项目比例 | > 95% |
| 漏洞发现平均时间 | 从引入到发现的时间 | < 1天 |
| 高危漏洞修复时间 | MTTR for High+ | < 7天 |
| 严重漏洞修复时间 | MTTR for Critical | < 1天 |
| 安全门禁通过率 | 首次通过比例 | > 80% |
| 误报率 | 抑制规则占比 | < 10% |
持续改进流程:
建立安全知识库:
# 安全知识库
## 常见漏洞修复指南
### Log4j 相关
– 受影响版本:2.0-beta9 到 2.14.1
– 修复版本:>= 2.17.1
– 修复方法:升级依赖版本
### Spring Framework
– …
## 抑制规则库
### 已批准的抑制规则
– [H2 Database](link-to-rule)
– [Test Dependencies](link-to-rule)
第七部分:常见问题与故障排查
Q1:首次扫描为什么这么慢?
A: 首次扫描需要下载完整的 NVD 数据库(约 2GB),可能需要 2-4 小时。后续扫描会快很多。
详细说明:
- NVD 数据库包含所有已公开的漏洞信息
- 下载速度取决于网络带宽和 NVD API 限制
- 使用 NVD API Key 可以显著提升下载速度(从每分钟 5 次请求提升到 50 次)
- 数据库会缓存在本地,后续扫描只需下载增量更新
优化建议:
# 1. 申请 NVD API Key(强烈推荐)
# 访问 https://nvd.nist.gov/developers/request-an-api-key
# 2. 首次运行时仅更新数据库
dependency-check.sh –nvdApiKey YOUR_API_KEY –updateonly
# 3. 使用 Docker 方式持久化缓存
docker run –rm \\
-v $(pwd)/dc-data:/usr/share/dependency-check/data \\
owasp/dependency-check:latest \\
–nvdApiKey YOUR_API_KEY \\
–updateonly
Q2:如何处理误报?
A: 使用抑制文件(suppression file),详见 4.3 节。
常见误报场景:
| 测试依赖漏洞 | 测试环境不受影响 | 使用 <suppression> 排除 |
| 内部库误匹配 | CPE 标识符冲突 | 使用 <packageUrl> 精确匹配 |
| 已修复但未更新 | 供应商延迟发布 | 使用 <cve> 指定 CVE |
| 不受影响版本 | 代码路径不可达 | 使用 <notes> 记录原因 |
抑制文件示例(dependency-check-suppressions.xml):
<?xml version="1.0" encoding="UTF-8"?>
<suppressions>
<!– 排除测试依赖 –>
<suppress>
<notes><![CDATA[
测试依赖,生产环境不受影响
]]></notes>
<packageUrl regex="true">^pkg:maven/org\\.junit/.*$</packageUrl>
</suppress>
<!– 排除特定 CVE(已确认不适用) –>
<suppress>
<notes><![CDATA[
CVE-2021-44228 不适用,项目使用 log4j 1.2.17
]]></notes>
<cve>CVE-2021-44228</cve>
</suppress>
<!– 排除特定版本的漏洞 –>
<suppress>
<notes><![CDATA[
内部库,已通过代码审查确认安全
]]></notes>
<packageUrl regex="true">^pkg:maven/com\\.company/internal-lib@.*$</packageUrl>
<cve>CVE-2023-12345</cve>
</suppress>
</suppressions>
抑制文件管理最佳实践:
Q3:内网环境如何使用?
A: 有两种方案:1)离线下载漏洞数据库;2)搭建本地 NVD 镜像。
方案一:离线下载漏洞数据库
# 步骤 1:在有外网的机器上下载完整数据库
dependency-check.sh –nvdApiKey YOUR_API_KEY –updateonly –data /path/to/data
# 步骤 2:打包数据库目录
cd /path/to
tar -czf dependency-check-data.tar.gz data/
# 步骤 3:传输到内网机器(使用 U 盘、内网传输等)
# 步骤 4:在内网机器上解压
tar -xzf dependency-check-data.tar.gz -d /opt/dependency-check/
# 步骤 5:配置数据目录
dependency-check.sh \\
–data /opt/dependency-check/data \\
–project "MyProject" \\
–scan ./src \\
–out ./reports \\
–noupdate # 关键:不尝试更新数据库
方案二:搭建本地 NVD 镜像
# 使用开源工具搭建本地镜像
# 参考:https://github.com/dependency-check/Dependency-Check/issues/4249
# 方案 A:使用代理服务器
# 配置 Dependency-Check 使用代理
dependency-check.sh \\
–proxy.server proxy.company.com \\
–proxy.port 8080 \\
–proxy.username user \\
–proxy.password pass \\
–scan ./src
# 方案 B:使用本地漏洞数据库同步工具
# 定期从外网同步 NVD 数据到内网服务器
# 内网项目指向本地数据库服务器
内网环境注意事项:
- 漏洞数据库需要定期更新(建议每周一次)
- 离线模式无法获取最新的漏洞信息
- 考虑使用商业 SCA 工具,它们通常提供离线数据库支持
Q4:扫描失败怎么办?
A: 检查以下几点:
- 网络连接是否正常
- NVD API Key 是否有效
- 磁盘空间是否充足
- Java 版本是否符合要求
详细排查步骤:
1. 检查网络连接
# 测试 NVD 服务是否可达
curl -I https://nvd.nist.gov/
# 测试 API Key 是否有效
curl -H "apiKey: YOUR_API_KEY" \\
https://services.nvd.nist.gov/rest/json/cves/2.0
2. 验证 NVD API Key
# API Key 格式应为 40 字符的十六进制字符串
# 示例:abcd1234-5678-90ef-ghij-klmnopqrstuv
# 检查环境变量
echo $NVD_API_KEY
# 如果 API Key 失效,重新申请:
# https://nvd.nist.gov/developers/request-an-api-key
3. 检查磁盘空间
# Linux/Mac
df -h
# Windows
dir
# Dependency-Check 需要的空间:
# – 数据库缓存:~2GB
# – 临时文件:~1GB
# – 报告文件:~100MB
# 总计建议:至少 5GB 可用空间
4. 验证 Java 版本
# 检查 Java 版本
java -version
# Dependency-Check 要求:
# – 最低:Java 8
# – 推荐:Java 11 或更高
# – 注意:Java 17+ 可能需要额外配置
# 如果版本不符合要求,安装正确的 Java 版本
5. 查看详细日志
# 启用调试日志
dependency-check.sh \\
–scan ./src \\
–out ./reports \\
–log debug \\
–logFile dependency-check-debug.log
# 查看日志文件
tail -f dependency-check-debug.log
常见错误及解决方案:
| Failed to connect to NVD | 网络问题或 NVD 服务不可用 | 检查网络,稍后重试 |
| API rate limit exceeded | 超过 NVD API 限制 | 申请 API Key 或等待重置 |
| OutOfMemoryError | 内存不足 | 增加 JVM 内存 -Xmx4g |
| Permission denied | 文件权限问题 | 检查目录权限 |
| Unsupported class file version | Java 版本不兼容 | 升级或降级 Java 版本 |
增加 JVM 内存:
# 命令行方式
export MAVEN_OPTS="-Xmx4g -Xms2g"
dependency-check.sh –scan ./src
# Maven 插件方式
<plugin>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId>
<configuration>
<jvmArgs>-Xmx4g -Xms2g</jvmArgs>
</configuration>
</plugin>
# Docker 方式
docker run –rm \\
-e JAVA_OPTS="-Xmx4g -Xms2g" \\
-v $(pwd):/src \\
owasp/dependency-check:latest \\
–scan /src
Q5:如何提升扫描速度?
A: 可以通过以下方式优化扫描性能:
1. 使用 NVD API Key
# 无 API Key:每分钟 5 次请求
# 有 API Key:每分钟 50 次请求(10倍提升)
# 设置环境变量
export NVD_API_KEY=your_api_key_here
# 或在命令行中指定
dependency-check.sh –nvdApiKey YOUR_API_KEY –scan ./src
2. 持久化数据缓存
# Docker 方式:映射数据目录
docker run –rm \\
-v $(pwd)/dc-data:/usr/share/dependency-check/data \\
-v $(pwd):/src \\
owasp/dependency-check:latest \\
–scan /src
# 命令行方式:指定数据目录
dependency-check.sh \\
–data /opt/dependency-check/data \\
–scan ./src
3. 禁用不必要的分析器
# 只启用需要的分析器
dependency-check.sh \\
–disableRetireJS \\
–disableNodeJS \\
–disableNodeAudit \\
–scan ./src
# Maven 插件配置
<configuration>
<analyzers>
<jarAnalyzer>false</jarAnalyzer>
<npmAnalyzer>false</npmAnalyzer>
<pythonAnalyzer>false</pythonAnalyzer>
</analyzers>
</configuration>
4. 并行扫描(多模块项目)
# 使用 GNU Parallel 并行扫描
find . -name "pom.xml" -type f | parallel -j 4 \\
'dependency-check.sh –project {/.} –scan {//} –out reports/{/.}'
# Jenkins Pipeline 中使用并行 stage
parallel(
"module-a": { sh 'mvn -f module-a/pom.xml dependency-check:check' },
"module-b": { sh 'mvn -f module-b/pom.xml dependency-check:check' },
"module-c": { sh 'mvn -f module-c/pom.xml dependency-check:check' }
)
5. 优化扫描范围
# 只扫描必要的目录
dependency-check.sh \\
–scan ./target/classes \\
–scan ./target/lib \\
–out ./reports
# 排除不需要的目录
dependency-check.sh \\
–scan ./src \\
–exclude ./src/test \\
–exclude ./src/main/resources/static \\
–out ./reports
性能对比:
| 无优化(首次) | 2-4 小时 | 需要下载完整数据库 |
| 无优化(后续) | 30-60 分钟 | 仅增量更新 |
| + NVD API Key | 15-30 分钟 | 下载速度提升 10 倍 |
| + 数据缓存 | 5-10 分钟 | 跳过数据库更新 |
| + 禁用不必要分析器 | 3-5 分钟 | 减少分析时间 |
| + 并行扫描 | 1-3 分钟 | 利用多核 CPU |
Q6:如何集成到现有的 CI/CD 流程?
A: 根据使用的 CI/CD 工具,选择相应的集成方式。
GitHub Actions 集成:
name: Security Scan
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
schedule:
– cron: '0 2 * * *' # 每天凌晨 2 点
jobs:
dependency-check:
runs-on: ubuntu–latest
steps:
– uses: actions/checkout@v3
– name: Set up JDK 11
uses: actions/setup–java@v3
with:
java-version: '11'
distribution: 'temurin'
– name: Run Dependency–Check
uses: dependency–check/Dependency–Check_Action@main
with:
project: 'my-project'
path: '.'
format: 'HTML'
out: 'reports'
args: >
–nvdApiKey ${{ secrets.NVD_API_KEY }}
–failOnCVSS 7
–enableExperimental
– name: Upload Report
uses: actions/upload–artifact@v3
if: always()
with:
name: dependency–check–report
path: reports/
GitLab CI 集成:
stages:
– test
– security
dependency-check:
stage: security
image: owasp/dependency–check:latest
script:
– dependency–check.sh
––project "$CI_PROJECT_NAME"
––scan .
––out reports
––format HTML
––format JSON
––nvdApiKey $NVD_API_KEY
––failOnCVSS 7
artifacts:
paths:
– reports/
when: always
expire_in: 1 week
only:
– main
– merge_requests
Azure DevOps 集成:
trigger:
– main
pool:
vmImage: 'ubuntu-latest'
variables:
NVD_API_KEY: $(NVD_API_KEY)
steps:
– task: UseDotNet@2
inputs:
packageType: 'sdk'
version: '6.x'
– script: |
docker pull owasp/dependency-check:latest
docker run –rm \\
-v $(pwd):/src \\
-v $(pwd)/reports:/report \\
-e NVD_API_KEY=$NVD_API_KEY \\
owasp/dependency-check:latest \\
–scan /src \\
–out /report \\
–format ALL \\
–failOnCVSS 7
displayName: 'Run Dependency-Check'
– task: PublishBuildArtifacts@1
inputs:
PathtoPublish: 'reports'
ArtifactName: 'dependency-check-reports'
publishLocation: 'Container'
condition: always()
CircleCI 集成:
version: 2.1
orbs:
dependency-check: dependency–check/dependency–check@1.0.0
workflows:
security-scan:
jobs:
– dependency-check/scan:
path: '.'
project: 'my-project'
format: 'ALL'
failOnCVSS: 7
nvdApiKey: $NVD_API_KEY
filters:
branches:
only:
– main
– develop
Q7:如何设置安全门禁?
A: 根据项目安全要求,设置合适的 CVSS 阈值和阻断策略。
基础门禁配置:
# CVSS 阈值配置
dependency-check.sh \\
–failOnCVSS 7 \\
–scan ./src \\
–out ./reports
# Maven 插件配置
<plugin>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId>
<configuration>
<failBuildOnCVSS>7</failBuildOnCVSS>
</configuration>
</plugin>
分级门禁策略:
| 生产环境 | 阻断 | 阻断(>3个) | 警告 | 警告 |
| 预发布环境 | 阻断 | 警告 | 警告 | 忽略 |
| 测试环境 | 警告 | 警告 | 忽略 | 忽略 |
| 开发环境 | 忽略 | 忽略 | 忽略 | 忽略 |
Jenkins Pipeline 门禁示例:
pipeline {
agent any
environment {
NVD_API_KEY = credentials('nvd-api-key')
}
stages {
stage('Security Scan') {
steps {
script {
def scanResult = sh(
script: """
dependency-check.sh \\
–project "${env.JOB_NAME}" \\
–scan ./src \\
–out ./reports \\
–format JSON \\
–nvdApiKey ${NVD_API_KEY} \\
–failOnCVSS 7
""",
returnStatus: true
)
if (scanResult != 0) {
// 解析报告,获取漏洞详情
def report = readJSON file: 'reports/dependency-check-report.json'
def criticalVulns = report.dependencies.findAll {
it.vulnerabilities.any { it.cvssScore >= 9.0 }
}
if (criticalVulns) {
error "发现 ${criticalVulns.size()} 个严重漏洞,构建失败!"
}
}
}
}
}
}
post {
always {
publishHTML(target: [
reportDir: 'reports',
reportFiles: 'dependency-check-report.html',
reportName: 'Dependency-Check Report'
])
}
}
}
GitHub Actions 门禁示例:
– name: Check for Critical Vulnerabilities
run: |
# 解析 JSON 报告
CRITICAL_COUNT=$(jq '[.dependencies[].vulnerabilities[] | select(.cvssScore >= 9.0)] | length' reports/dependency-check-report.json)
if [ $CRITICAL_COUNT –gt 0 ]; then
echo "❌ 发现 $CRITICAL_COUNT 个严重漏洞"
exit 1
else
echo "✅ 未发现严重漏洞"
fi
Q8:如何处理大型项目的扫描?
A: 大型项目需要特殊的优化策略来平衡扫描速度和准确性。
策略一:增量扫描
# 只扫描变更的模块
git diff –name-only HEAD~1 HEAD | grep "pom.xml" | while read pom; do
module_dir=$(dirname "$pom")
dependency-check.sh \\
–project "$(basename $module_dir)" \\
–scan "$module_dir" \\
–out "reports/$(basename $module_dir)"
done
策略二:分层扫描
# 第一层:核心依赖(每次扫描)
dependency-check.sh \\
–project "core-deps" \\
–scan ./core/target/lib \\
–out ./reports/core
# 第二层:业务模块(按需扫描)
dependency-check.sh \\
–project "business-modules" \\
–scan ./modules/target/lib \\
–out ./reports/modules
# 第三层:测试依赖(低频扫描)
dependency-check.sh \\
–project "test-deps" \\
–scan ./test/target/lib \\
–out ./reports/test
策略三:分布式扫描
# 使用 Jenkins 分布式构建
pipeline {
agent none
stages {
stage('Parallel Security Scan') {
parallel {
stage('Module A') {
agent { label 'agent-1' }
steps {
sh 'mvn -f module-a/pom.xml dependency-check:check'
}
}
stage('Module B') {
agent { label 'agent-2' }
steps {
sh 'mvn -f module-b/pom.xml dependency-check:check'
}
}
stage('Module C') {
agent { label 'agent-3' }
steps {
sh 'mvn -f module-c/pom.xml dependency-check:check'
}
}
}
}
stage('Aggregate Results') {
agent any
steps {
sh 'mvn dependency-check:aggregate'
}
}
}
}
策略四:缓存优化
# 使用构建缓存
dependency-check.sh \\
–data /opt/dependency-check/data \\
–cache ./dependency-check-cache \\
–scan ./src \\
–out ./reports
# Maven 插件缓存配置
<plugin>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId>
<configuration>
<dataDirectory>/opt/dependency-check/data</dataDirectory>
<cacheDirectory>${project.build.directory}/dependency-check-cache</cacheDirectory>
</configuration>
</plugin>
大型项目扫描最佳实践:
| 小型(<50 依赖) | 全量扫描 | 每次 CI | 1-3 分钟 |
| 中型(50-200 依赖) | 增量扫描 | 每次 CI | 5-10 分钟 |
| 大型(200-500 依赖) | 分层扫描 | 每日/每周 | 15-30 分钟 |
| 超大型(>500 依赖) | 分布式扫描 | 每周 | 30-60 分钟 |
结语
写这篇文章的时候,我又想起了 Log4j2 那个晚上——整个技术圈都在熬夜排查漏洞,那种焦虑感至今记忆犹新。
说到底,安全不是什么高大上的概念,就是别让你的项目成为下一个"定时炸弹"。Dependency-Check 这类工具,本质上就是帮你提前发现隐患,把风险控制在可接受范围内。
几个关键点,再啰嗦一遍:
接下来怎么做?
别光看不练,选一个试点项目,按照本文案例配置 Dependency-Check。申请个 NVD API Key,优化扫描性能。建立团队的安全门禁策略和漏洞修复流程。逐步引入其他安全工具,构建完整的 DevSecOps 工具链。
安全这场仗没有终点,但至少我们可以把防线往前推一推。希望本文能帮你在快速交付的同时,把安全这道门守好。





