dist.sha256仅是内容指纹而非数字签名,只校验zip包字节一致性,不绑定发布者身份、不防元数据劫持、不覆盖autoload.php等引导文件,且镜像未同步哈希时校验仍“成功”。

dist.sha256 不是签名,只是内容指纹
dist.sha256 字段记录在 composer.lock 中,作用仅限于下载后比对 ZIP 包字节是否与 Packagist 存档一致。它不绑定发布者身份,也不防元数据劫持——镜像站若替换了 dist.url 但没同步原始哈希(比如阿里云、腾讯云镜像常见做法),校验照样“成功”,而实际代码可能已被注入。
常见错误现象:composer install 成功、composer diagnose 显示 secure-http: OK,但线上运行时触发未声明的 post-install-cmd;或 vendor/ 中某文件被篡改,却未报错。
-
dist.sha256为空时,verify-checksums --strict直接跳过,不提示也不失败 -
--prefer-source或"preferred-install": {"*": "source"}会绕过整个dist校验链 -
vendor/autoload.php等引导文件不在哈希覆盖范围内,被改写也不会触发告警
signature verification: OK 才是真正的信任锚点
Packagist 官方签名(不是用户侧的 GPG)才是防中间人攻击的核心机制。它由 Packagist 服务端为每个包版本生成并内嵌在元数据中,Composer 2.5+ 默认启用,但前提是不能用 repo.packagist 全局替换源——否则签名字段直接丢失。
正确配置必须满足三点:repos.packagist.type composer + repos.packagist.url https://mirrors.aliyun.com/composer/(注意尾斜杠)+ security.signature-verification true。只有这样,composer diagnose 输出才会同时出现 secure-http: OK 和 signature verification: OK。
- 执行
composer config -g repo.packagist false是必要前置动作,否则旧式源替换会彻底关闭签名验证 - 镜像 URL 必须带尾斜杠,否则 Composer 会误判为普通仓库而非元数据代理
- 若
composer show --security输出不含Signature verification: enabled,说明签名未生效,此时所有哈希校验都不可信
verify-checksums --strict 是 vendor 层唯一落地校验手段
verify-checksums 命令本身不联网、不查元数据,只读取本地 vendor/ 并逐包计算 SHA256,再跟 composer.lock 中对应 dist.sha256 比对。但它默认不严格:哈希不匹配只警告,返回码仍是 0,CI 会误判成功。
必须加环境变量和参数:COMPOSER_EXPERIMENTAL=1 composer verify-checksums --strict。否则哪怕 vendor/monolog/monolog/src/Logger.php 被悄悄替换成恶意代码,也不会中断构建。
- 该命令跳过
type: "package"和type: "path"的包,且不报错 - 私有源或老旧包若没打 dist zip,
composer.lock中dist.sha256为空,校验直接忽略 - 它不校验
autoload配置文件、scripts注册函数、或extra中任意键值,这些地方常被供应链攻击利用
composer.lock 是离线防劫持的最后一道闸
只要 composer.lock 完整提交进 Git,composer install 就完全不发网络请求——它只从 ~/.composer/cache/files 读 ZIP 并比对哈希。DNS 劫持、镜像污染、中间人攻击,全被挡在门外。
关键约束非常简单:composer.lock 必须进 Git,禁止出现在 .gitignore;且任意包的 "dist": { "sha256": "a1b2c3..." } 字段长度必须是 64(SHA-256),不能是 40(SHA-1)或空字符串。
- CI 构建前应加检查脚本:
grep -q '"sha256": "[a-f0-9]\{64\}"' composer.lock || exit 1 - 部署时若发现
vendor/中文件哈希与composer.lock不匹配,说明本地缓存或镜像已被污染,必须清空~/.composer/cache/files后重装 - 别依赖镜像站的“同步时间戳”或“健康状态页”,最可靠的验证永远是本地哈希比对











