composer install 无报错但包内容错误,因默认不强制校验完整性:仅首次安装或 --no-cache 时比对 dist.sha256,且缓存存在则跳过;镜像替换、本地缓存污染、source 安装均绕过校验。

composer install 时为什么没报错,但包内容却不对?
因为默认情况下 Composer 不强制校验包完整性,它只比对 composer.lock 中记录的 dist.sha256(或 sha1)与下载后文件的哈希值——但仅限于从 Packagist 下载的 dist 包(zip/tar),且仅在首次安装或 composer install --no-cache 时触发。如果缓存中已有文件,Composer 会直接复用,跳过哈希比对。
- 本地缓存污染(比如手动改过
vendor/或缓存目录被篡改)会导致校验失效 - Packagist 的
dist包若被镜像源替换(如国内某些镜像未同步签名),哈希可能匹配但内容已非原始作者发布 -
source安装方式(如"type": "package"或pathrepo)完全不走哈希校验
如何启用强制哈希校验并验证现有 vendor?
Composer 本身没有「全局开关」来让每次 install/update 都重新计算并比对哈希,但可通过组合命令逼近效果:
- 清空缓存再重装:
composer clear-cache && composer install --no-cache,此时会重新下载 dist 包并校验dist.sha256 - 手动校验当前
vendor/:用composer show --locked --format=json提取每个包的dist.sha256,再用shasum -a 256 vendor/{package}/composer.json(注意:实际校验的是 dist 包解压后的根目录哈希,不是单个文件;官方不暴露校验逻辑细节,所以无法 100% 手动复现) - 更可靠的做法是使用
composer validate --strict检查composer.json和composer.lock结构一致性,但它不校验文件内容
签名(Satis / Private Packagist)和哈希哪个更可信?
哈希(如 sha256)只能防意外损坏或传输错误;签名(如 GPG)才能防恶意篡改——前提是你的 Composer 配置信任该签名公钥,并且源本身支持签名分发。
- Packagist.org 不提供包签名,只提供哈希,所以你依赖的是 Packagist 服务器自身的安全性
- Private Packagist 支持 GPG 签名验证,需在
composer.json中配置"signature" : true并导入对应公钥 - Satis 不内置签名机制,需自行在生成仓库时用
gpg --clearsign签署packages.json,再配合自定义脚本验证 - 签名验证失败时 Composer 会抛出
InvalidSignatureException错误,而哈希不匹配通常只警告或静默跳过
CI/CD 中怎么防止依赖被悄悄替换?
靠本地 composer install 默认行为不够。关键是在构建流程中切断缓存干扰、锁定来源、并做二次校验:
- CI 中始终使用
composer install --no-cache --prefer-dist --optimize-autoloader,避免复用不可信缓存 - 把
composer.lock提交进 Git,并在 CI 中加一步校验:git diff --quiet composer.lock || (echo "lock file changed unexpectedly"; exit 1) - 对高敏感项目,可额外运行
composer show --locked --format=JSON | jq -r '.packages[] | select(.dist) | "\(.name) \(.dist.sha256)"',与上一次构建的哈希快照比对 - 别忽略
require-dev——它们同样参与 autoloader 生成,一旦被污染,测试环境可能掩盖运行时问题










