composer默认不验证包体gpg签名,仅通过https+tls证书+composer.lock中sha-256哈希比对三层机制保障完整性;唯一启用gpg的场景是packagist元数据签名验证(需composer≥2.2且配置signing-key),用于防仓库投毒。

Composer 默认不验证包体 GPG 签名,只校验 SHA-256 哈希和 https 传输链
Composer 本身**不会对每个下载的 .zip/.tar 包执行 GPG 解签名**——它不内置 GPG 引擎,也不要求包作者上传 .sig 文件。所谓“签名验证”,实际是三层防御:HTTPS 连接加密 + 服务器证书可信(TLS 验证)+ composer.lock 中记录的 dist.shasum 哈希比对。这三者缺一不可,但都不是传统意义的“数字签名”。
- 运行
composer install时,Composer 会自动读取composer.lock里的"shasum": "a1b2c3...",并和远程 zip 包的实际 SHA-256 值比对;不一致就报错Signature mismatch, package is corrupted - TLS 验证由
src/Composer/Util/TlsHelper.php执行,依赖 PHP 的 OpenSSL 扩展和系统 CA 证书库;若证书异常(如自签名),会直接中断连接 - Packagist 的元数据(
packages.json)自 2021 年起支持 GPG 签名,但需 Composer ≥ 2.2 且启用signing-key配置才触发校验——默认未开启
如何启用 Packagist 元数据 GPG 签名验证(防仓库投毒)
这是目前 Composer 生态中唯一真正用到 GPG 的签名验证场景,目标是防止攻击者篡改 Packagist 的包索引,把恶意包混进搜索结果。它不校验包内容,只校验索引文件本身是否被 Packagist 私钥签署过。
- 确认版本:
composer --version输出必须 ≥2.2.0 - 设置全局配置:
composer config --global signing-key https://packagist.org/keys.json(该 URL 返回的是 Packagist 官方公钥列表) - 确保
secure-http: true和disable-tls: false在composer.json或全局 config 中生效 - 验证是否生效:删掉
vendor/和composer.lock,运行composer install -v,观察日志中是否出现Verifying packages.json signature with key ...
注意:keys.json 是动态更新的,Composer 不会自动轮换密钥;如果某天 Packagist 更换主密钥,旧版 Composer 可能因找不到对应公钥而拒绝加载包列表。
想验证具体包的 git 标签签名?得绕开 Composer 自己动手
Composer 对 Git 仓库(VCS 类型依赖)只做克隆和检出,**不调用 git tag -v**。如果你真关心某个包是否由作者用 GPG 签过 tag(比如 v2.5.0),就得手动操作:
- 先从
composer show vendor/package查看源地址,或翻composer.lock的source.url字段 - 用
git clone拉下仓库,再运行git tag -v v2.5.0;输出含Good signature from "Name <email>"</email>且密钥已导入本地 GPG 环境才算可信 - 在
composer.json中显式指定带签名的 tag:"dev-master#v2.5.0"或"2.5.0"(前提是minimum-stability设为stable) - 别依赖
dev-main或dev-develop—— 这些分支头提交几乎从不签名
常见失效场景和排查路径
很多人以为“开了 HTTPS 就等于安全”,结果还是栽在细节上。最常踩的坑不是技术不会用,而是没意识到验证链条在哪断了。
-
composer install没报错 ≠ 包没被篡改:如果项目没提交composer.lock,或用了--ignore-platform-reqs跳过哈希检查,那dist.shasum校验根本不会触发 - 私有仓库用 HTTP?
"secure-http": true会直接拒绝加载,错误是Repository ... is not secure,不是证书问题 - 自签名证书环境(如内网 gitlab),必须配置
composer config --global cafile /path/to/cert.crt,否则 TLS 验证失败,连包列表都拉不下来 - CI 环境里
openssl.cafile没配对?PHP CLI 和 Web SAPI 的php.ini常是两套,php -r "print_r(openssl_get_cert_locations());"可查实际路径
真正关键的不是“有没有签名”,而是你清楚每一步校验发生在哪、谁负责执行、失败时抛什么错。包来源可信这件事,从来不是按一个按钮就能解决的。