首页
/ Trivy 扫描 PHP Composer 依赖:composer.lock 与 installed.json 的漏洞、许可证与依赖图检测完全指南

Trivy 扫描 PHP Composer 依赖:composer.lock 与 installed.json 的漏洞、许可证与依赖图检测完全指南

2026-09-08 19:43:11作者:幸俭卉

本篇指南基于 Trivy 开源仓库中的 docs/guide/coverage/language/php.md,完整讲解 Trivy 如何对 PHP 项目进行依赖安全扫描。Trivy 通过 Composer 生态的 composer.lockvendor/composer/installed.json 两类清单文件,实现 SBOM 生成、漏洞检测与许可证识别,并支持依赖树与开发依赖(dev dependencies)的精细控制。读完本文,你将掌握 Trivy 扫描 PHP 项目支持的扫描器与文件矩阵、依赖树与直连/间接依赖的判定原理、--include-dev-deps 的用法与配置方式,以及底层解析与后处理的具体实现路径。

PHP 支持的扫描能力概览

Trivy 对 PHP 生态的依赖管理工具 Composer 提供了完整支持。原始文档明确说明 Trivy 支持 Composer 这一 PHP 依赖管理工具,并支持以下三类扫描器:

Package manager SBOM Vulnerability License
Composer

也就是说,针对 Composer 管理的依赖,Trivy 既可以生成 SBOM(软件物料清单),也可以逐包匹配漏洞库给出漏洞结果,还能识别每个依赖包的许可证信息,为许可证合规审计提供依据。

依赖清单文件支持矩阵

Trivy 主要识别两种由 Composer 生成的清单文件,其能力矩阵如下:

Package manager File Transitive dependencies Dev dependencies Dependency graph Position
Composer composer.lock Excluded
Composer installed.json Excluded -

表中信息可以解读为:

  • Transitive dependencies:两种文件都能还原传递(间接)依赖,扫描结果不只覆盖直接声明的包;
  • Dev dependenciescomposer.lock 默认排除开发依赖,但可以通过 --include-dev-deps 开启;installed.json 场景下开发依赖始终被排除;
  • Dependency graph:仅 composer.lock 支持输出依赖图(用于定位漏洞来源链路),installed.json 不支持;
  • Position:两者都支持记录包在文件中的位置(行号区间),便于结果回溯到具体清单条目。

在源码层面,这些类型常量统一定义于 pkg/fanal/types/const.go

  • Composercomposer)与 ComposerVendorcomposer-vendor)是两种语言类型(LangType,见该文件 L106-L107);
  • composer.lockcomposer.jsoninstalled.json 三个文件名常量见该文件 L219-L221。

何时使用哪种文件

  • 源码仓库 / 制品目录通常包含 composer.lock,Trivy 推荐以它为主要扫描对象;
  • 若仓库中没有提交 composer.lock,但已执行过 composer install(生成了 vendor/ 目录),则其中的 vendor/composer/installed.json 可退而成为依赖检测来源,覆盖真实安装到 vendor/ 中的包集合。

composer.lock 检测机制

为探测依赖,Trivy 会在被扫描的目标(镜像、文件系统、代码仓库等)中递归搜索 composer.lock。这是文档明确声明的行为;在实现上,Composer 分析器注册为 analyzer.TypeComposer 类型的后处理分析器(PostAnalyzer),见 pkg/fanal/analyzer/language/php/composer/composer.go

  • 第 25-27 行通过 init() 调用 analyzer.RegisterPostAnalyzer(analyzer.TypeComposer, newComposerAnalyzer) 注册;
  • 第 31-34 行的 requiredFiles 同时包含 composer.lockcomposer.json
  • 第 46-79 行的 PostAnalyze 遍历文件系统,凡文件名是 composer.lock 或命中用户自定义文件模式(FilePatterns.Match)的文件都会送入 parseComposerLock 解析;
  • 第 81-92 行的 Required 方法补充了一个重要细节:位于 vendor 目录内部的 composer.lock 会被主动跳过(第 87-90 行),避免重复或误扫由 Composer 安装在 vendor 下的嵌套锁文件。

值得注意,composer.json 本身并不产生独立的依赖应用(Application),它只在同目录存在 composer.lock 时作为补充数据被合并解析。

为什么显示准确依赖树需要 composer.json

composer.lock 记录的是 Composer 锁定后的完整依赖集合,但它并不包含每个包是项目直接依赖还是传递依赖的信息。文档指出:为了显示准确的依赖树,Trivy 需要知道每个包是否为项目的直接依赖;由于该信息不包含在 composer.lock 中,Trivy 会解析与 composer.lock 同目录的 composer.json。因此,若你想看到依赖树,请确保 composer.jsoncomposer.lock 同时存在

这一机制在源码中有清晰对应。mergeComposerJson 函数(composer.go 第 106-131 行)在解析锁文件后查找其所在目录的 composer.json,将其中 require(运行时依赖)与 require-dev(开发依赖)的键与每个包名做匹配:

  • 命中 requirerequire-dev → 标记为 RelationshipDirect(直接依赖,Indirect=false);
  • 未命中 → 标记为 RelationshipIndirect(间接依赖,Indirect=true)。

若找不到 composer.json,Trivy 会以 Debug 级别记录日志并放弃修正(第 110-113 行),此时所有包的关系保持为 RelationshipUnknown。测试用例 composer_test.go 中名为 no composer.jsonwrong composer.json 的用例验证了这一行为:缺少或无法解析 composer.json 时,结果中包的关系字段为 RelationshipUnknown;而 happy path 用例则展示了在 composer.json 存在时,pear/log 被正确判定为 Direct、其依赖 pear/pear_exception 被判定为 Indirect。

Development dependencies(开发依赖)

默认情况下,Trivy 不报告开发依赖(即 composer.lock 中的 packages-dev 字段)。如需将其纳入结果,使用 --include-dev-deps 标志。

这一标志在源码中的定义位于 pkg/flag/package_flags.go

  • 第 10-13 行声明 IncludeDevDepsFlag,命令行名称为 include-dev-deps,对应配置键名为 pkg.include-dev-deps
  • 第 44-50 行的选项结构体与其绑定,运行时通过 pkg/flag/options.go 第 526 行把该值传递到扫描选项。

因此除了命令行标志外,你也可以在 trivy.yaml 中使用等价配置开启,例如:

pkg:
  include-dev-deps: true

为了正确识别直接开发依赖,Trivy 需要解析与 composer.lock 同目录的 composer.json 中的 require-dev 字段(见 composer.go 第 122-123 行的匹配逻辑,以及第 133-136 行 composerJson 结构体对 require-dev 的解析)。

在解析阶段,开发依赖并非简单丢弃,而是先被解析并打上标记:底层解析器 Parser(见 pkg/dependency/parser/php/composer/parse.go)的第 19-22 行定义了 LockFile,同时包含 packagespackages-dev 两组;第 50-53 行先解析生产依赖、再解析开发依赖;第 80-96 行注释明确指出:packages-dev 中已经存在于生产包集合里的同名包会被跳过,生产包优先。测试用例 with dev dependenciescomposer_test.go)中,开发包 pear/log@1.14.6pear/pear_exception@v1.0.2 均带有 Dev: true 标记。是否在最终报告输出这些 Dev 包,则由 --include-dev-deps 决定。

installed.json(vendor 目录)

composer.lock 外,Trivy 也支持对 installed.json 文件的依赖检测。按文档说明,该文件在默认安装布局下的路径是 path_to_app/vendor/composer/installed.json——即执行过 composer install 后由 Composer 生成、位于 vendor/composer/ 目录内的安装清单。

其分析器实现在 pkg/fanal/analyzer/language/php/composer/vendor.go

  • 第 14-16 行以 analyzer.RegisterAnalyzer 注册 composerVendorAnalyzer(类型 composer-vendor,版本 1);
  • 第 29-31 行的 Required 判定文件基名是否为 installed.json
  • 第 25-27 行复用与 composer.lock 相同的 composer.NewParser(),保证两种清单产出的包模型与解析口径一致。

installed.json 的典型结构以一个 packages 数组为主,每个元素包含 nameversionrequirerequire-devlicensetypetime 等字段。仓库中的样例文件见 testdata/composer-vendor/happy/installed.json,其结构可以直接对照参考。

对比 composer.lockinstalled.json 场景的限制在于:依赖图(Dependency graph)列标注为 -(不支持),且开发依赖被排除,无法像 composer.lock 那样通过 composer.jsonrequire-dev 还原直接开发依赖关系。因此,若你的目标是获得完整依赖树或启用依赖图定位漏洞源头,应优先保证 composer.lock(以及同目录的 composer.json)可被 Trivy 访问。

底层解析与实现细节

依赖解析与"php / ext"过滤

通用解析器 pkg/dependency/parser/php/composer/parse.go 负责把 JSON 清单转成 Trivy 内部包模型,其关键逻辑如下:

  • 包 ID 生成:第 99 行通过 dependency.ID(ftypes.Composer, lpkg.Name, lpkg.Version) 生成形如 vendor/name@version 的唯一 ID;
  • 依赖边还原:第 57-71 行遍历每个包的 require 字段构建 DependsOn,随后在第 75 行统一排序,形成稳定的依赖图输出;因为 require 里是版本区间而非精确版本,具体版本号会回填自锁文件中实际存在的包(见第 60-62 行);
  • 平台/扩展过滤:第 109-117 行构造 DependsOn 时跳过 php 本身以及所有 ext-* 开头的 PHP 扩展(如 ext-jsonext-curl),因为这些并不是可匹配漏洞库的第三方包;
  • 位置信息:第 104 行通过 xjson.Location 内嵌捕获每个包在 JSON 文件中的起止行号,这是上文能力矩阵中 Position 列的实现基础。

以上行为可对照真实锁文件样例 pkg/dependency/parser/php/composer/testdata/composer_happy.lock 验证:例如 guzzlehttp/guzzlerequire 中包含 "php": ">=5.5""ext-json": "*" 等平台/扩展条目,解析时它们不会成为依赖边。

许可证字段的多种形态

Composer 的许可证字段(license)形态并不固定:可能是单个字符串(如 "MIT")、带分隔符的复合表达式(如 "MIT or BSD-2-Clause"),也可能是字符串数组(如 ["MIT"])。解析器第 124-141 行的 licenses 函数专门兼容了这两种形态:

  • 字符串类型会交给 licensing.SplitLicenses 拆分复合表达式(orand 等分隔符);
  • 数组类型则逐元素提取字符串,忽略非字符串元素。

该函数的注释还指出其格式约定来源于 Composer 的 schema 文档(getcomposer.org/doc/04-schema.md#license)。在 composer_test.go 的 happy path 用例中,pear/log 的许可证 MITpear/pear_exceptionBSD-2-Clause 都被正确解析出来,印证了 License 扫描器的数据来源。

测试验证路径

对 PHP/Composer 能力的单元测试覆盖在以下文件中,可作为深入理解与二次开发的参考:

实战:扫描一个 PHP 项目

将以上机制用于实际项目,只需要保证目标中可被 Trivy 发现 composer.lock(推荐)或 vendor/composer/installed.json。以下命令均为常规查看与运行方式:

# 扫描本地 PHP 项目目录(默认不含开发依赖)
trivy fs /path/to/php-project

# 将开发依赖一并纳入扫描
trivy fs --include-dev-deps /path/to/php-project

# 扫描包含 PHP 应用的容器镜像
trivy image your-registry/your-php-app:tag

# 扫描远端代码仓库
trivy repo https://your-host/your-php-app.git

如果要始终包含开发依赖,可以在 trivy.yaml 中写入上文所述的 pkg.include-dev-deps 配置,从而免去每次追加标志。

需要留意两点:

  1. 依赖树需要 composer.json:若希望 --report dependency-tree 或结果中包含准确的依赖关系,请确保 composer.jsoncomposer.lock 位于同一目录;
  2. vendor 内的锁文件会被跳过:由于 composer.lock 的 Required 检查会排除 vendor 目录下的同名文件,请确保待扫描的项目根目录持有自己生成的锁文件。

当你在报告中使用 --show-origins(显示漏洞依赖来源)等能力时,Trivy 会基于上述依赖边构建的依赖图回溯漏洞的引入链路,具体输出配置可参见文档 docs/guide/configuration/reporting.md

小结

  • Trivy 对 PHP 的 Composer 生态同时支持 SBOM、漏洞与许可证三种扫描器,依赖清单来源是 composer.lockinstalled.json
  • 两者都能还原传递依赖并记录包位置;composer.lock 额外支持依赖图,且可通过 composer.json 精确区分直连/间接依赖;
  • 开发依赖默认不报告,使用 --include-dev-deps(或 pkg.include-dev-deps 配置)开启;
  • 从源码看,composer.lockinstalled.json 共用同一解析器 parse.go,但由两个不同的分析器(composer.govendor.go)驱动,前者跳过 vendor 目录并合并 composer.json 做直连关系标注,后者仅按 installed.json 基名触发。

把 PHP 项目的锁文件与 composer.json 一起纳入版本管理,并让 Trivy 在 CI 中常态化扫描它们,是让 Composer 依赖漏洞与许可证风险尽早暴露的低成本做法。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
898
5.82 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
921
1.84 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.8 K
1.02 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
531
596
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.02 K
519
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.36 K
1.46 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
391