3. 依赖风险分类与威胁建模
依赖风险治理的第一步不是“扫描”,而是把风险说清楚。一个依赖包出问题,可能不是因为它有 CVE,而是因为它的许可证与产品分发方式冲突,或者作者已经两年不维护,或者它间接引入了带后门的传递依赖。不同风险类型的触发条件、影响面、检测手段和处置策略完全不同。如果把它们混在一个“高危”标签里,团队就无法判断优先级,也无法向法务、安全和业务方解释为什么必须替换某个组件。
本节把依赖风险拆成六类,并给出针对不同依赖类型的威胁建模方法。核心思路是:先分类,再建模,最后才谈扫描和修复。分类解决“这是什么风险”,建模解决“攻击者或失败场景如何利用它”。
六类依赖风险的本质差异
许可证风险关注的是法律边界,而不是代码质量。常见冲突包括:GPL-3.0 要求衍生作品以相同许可证开源,若公司产品是闭源分发,就会触发合规问题;AGPL 进一步把网络服务也算作分发;SSPL 则对云服务商有特殊限制。许可证风险的特点是“代码能跑,但法律上不能这么用”。检测方式通常是扫描依赖树中的 license 字段,并结合分发模式(SaaS、私有部署、嵌入式)判断。
安全漏洞是最容易被工具覆盖的一类。它关注已知 CVE、CWE 或 GitHub Advisory,核心参数是 CVSS 分数、可利用性、是否可达。但“有漏洞”不等于“有风险”:一个只在测试代码中调用的反序列化漏洞,和生产环境暴露的远程命令执行漏洞,优先级相差极大。因此漏洞风险必须结合调用链可达性来判断。
维护停滞是“未来风险”。一个包可能当前没有漏洞,但最后一次提交在 2021 年,issue 堆积、无安全响应流程。一旦爆出新 CVE,可能无人修复。衡量指标包括:最近提交时间、发布频率、未关闭 issue 比例、维护者数量、是否有安全政策文件。
恶意代码是主动攻击。典型场景包括:包名仿冒(typosquatting)、依赖混淆(dependency confusion)、维护者账号被劫持后发布带后门版本、安装脚本执行恶意命令。这类风险不依赖 CVE,扫描器往往无法识别,需要结合包来源、发布者变更、安装脚本行为、哈希比对来判断。
数据泄露关注依赖是否会把敏感数据传出。例如,某个分析 SDK 默认上报设备信息、某个日志库把请求体写入第三方端点、某个 AI 依赖把 prompt 发送到外部 API。这类风险常出现在前端、移动端和数据处理链路中,需要结合网络出口、配置项和隐私政策审查。
合规风险是前几类的综合结果,但更强调监管要求。例如金融行业要求软件物料清单(SBOM)、医疗设备要求 FDA 网络安全提交、欧盟 CRA 要求漏洞披露流程。合规风险不一定来自单个依赖,而来自“你是否能证明自己知道用了什么、能否在 24 小时内响应”。
针对不同依赖类型的威胁建模方法
威胁建模不是对每个包都做一遍 STRIDE,而是根据依赖类型选择不同的分析路径。下面按四种典型依赖类型展开。
直接依赖:以“接口契约”为中心建模。直接依赖是你主动引入的,威胁建模应聚焦在“它暴露了什么接口、你如何使用它”。例如,一个直接依赖的 HTTP 客户端库,攻击面是它解析响应时的反序列化逻辑;触发条件是服务端返回恶意 payload;影响范围是进程内存和后续请求。建模时可以用数据流图:输入(网络响应)→ 处理(解析)→ 输出(对象/异常)。如果解析过程没有边界检查,就是高风险点。处置策略通常是升级到修复版本,或在外层增加校验。
传递依赖:以“依赖树路径”为中心建模。传递依赖数量通常是直接依赖的 5~10 倍,且你无法直接控制。威胁建模的关键是找到“最短攻击路径”:从你的直接依赖出发,经过哪些中间包,最终到达有漏洞或恶意的包。例如,A 依赖 B,B 依赖 C,C 存在反序列化漏洞。如果 A 的调用链不会触发 C 的漏洞函数,风险就低;如果 A 在启动时就会调用,风险就高。建模输出应是一张依赖路径图,标注每条路径上的版本、许可证、已知漏洞和维护状态。
构建时依赖:以“供应链完整性”为中心建模。构建时依赖包括编译器插件、打包工具、代码生成器、CI 镜像中的工具。它们不进入运行时制品,但能在构建阶段注入恶意代码。典型威胁是:攻击者劫持一个构建插件,在编译时向产物中插入后门。建模时应关注:依赖来源是否可信、是否有哈希校验、构建环境是否隔离、产物是否可复现。处置策略包括锁定版本、校验哈希、使用私有镜像、启用可复现构建。
运行时依赖:以“权限与数据流”为中心建模。运行时依赖在生产环境加载,影响面最大。建模应关注它拥有什么权限、能访问什么数据、会向哪里发送数据。例如,一个日志库如果拥有文件系统写权限,就可能被利用来覆盖配置文件;一个分析 SDK 如果拥有网络权限,就可能外传用户数据。建模输出应是一张权限矩阵:依赖名称 × 文件系统 × 网络 × 环境变量 × 敏感数据。处置策略包括最小权限运行、网络出口白名单、数据脱敏。
一个可操作的威胁建模检查表
下面给出一个针对单个依赖的威胁建模检查表,可直接用于评审或自动化脚本的字段设计。字段值均为示例,实际使用时按项目情况填写。
| 检查项 | 示例值 | 判断依据 |
|---|---|---|
| 依赖名称与版本 | log4j-core 2.14.1 | 来自 SBOM 或 lock 文件 |
| 依赖类型 | 传递依赖(A → B → log4j) | 依赖树路径分析 |
| 许可证 | Apache-2.0 | 与闭源分发兼容 |
| 已知漏洞 | CVE-2021-44228(CVSS 10.0) | NVD / GitHub Advisory |
| 调用链可达性 | 是,启动时加载 JNDI 配置 | 静态分析 + 运行时探针 |
| 维护状态 | 活跃,最近提交 3 天前 | 仓库提交记录 |
| 网络出口 | 可发起 LDAP 请求 | 代码审计 / 网络策略 |
| 处置策略 | 升级至 2.17.1,并限制 JNDI 出口 | 修复版本 + 缓解措施 |
最后强调一个常见误区:不要试图用一张图覆盖所有依赖。正确的做法是分层建模——先按依赖类型分组,再对每组选择最合适的威胁模型。直接依赖看接口,传递依赖看路径,构建时依赖看完整性,运行时依赖看权限。这样得到的风险清单才具有可操作性,也才能与许可证、合规、数据泄露等非漏洞类风险放在同一张治理看板上比较优先级。