唯一可靠方式是dev-branch#commit-hash格式,因Composer仅此语法触发VCS强制检出指定commit;@会被误解析为分支名,短哈希不唯一,且需40位完整哈希、真实分支名及VCS源支持。

直接锁定特定 Git Commit 是 Composer 供应链安全最可控的手段,但必须用 dev-branch#commit-hash 格式,其他写法(比如 @、sha1 单独作版本号)都会失败或被绕过。
为什么 dev-main#abc123... 是唯一可靠方式
Composer 的版本解析器把 # 后面的部分当作“分支别名的 commit 锚点”,只有这个语法能触发 VCS 驱动强制检出指定 commit;@ 是包名/版本分隔符,dev-main@abc123 会被当成一个叫 dev-main@abc123 的分支去查,根本不存在;而直接写 "vendor/pkg": "abc1234567890" 会报 invalid version 错误。
-
dev-main#abc1234567890abcdef1234567890abcdef123456中的main必须是远程仓库真实存在的分支名(如develop、master),否则 clone 会 fallback 到 latest - 哈希必须是完整 40 位,短哈希(如
abc123)在某些 Git 版本下可能不唯一,导致检出错误 commit - 该机制依赖 Packagist 或私有源的 VCS 驱动支持;GitHub/GitLab 原生 OK,Satis 需确认启用了
vcs类型源
如何验证实际检出的就是目标 commit
光看 composer.lock 里的 source.reference 不够——它只记录当时解析结果,无法防 force-push 覆盖。必须检查已安装包的真实 Git HEAD。
- 进入包目录:
cd vendor/vendor/package && git rev-parse HEAD - 对比输出是否与
composer.lock中对应项的source.reference完全一致(注意大小写和长度) - CI 中建议加校验脚本:
composer show -s vendor/package | grep -q "abc1234567890$" - 若
git rev-parse失败,说明 vendor 下是 dist zip 包而非 Git 工作区——需确保未启用--prefer-dist或源配置中未设"no-api": true
签名验证必须手动开启且仅对部分包生效
Composer 2.5+ 默认仍不强制校验签名,require-signature: true 和全局 security.signature-verification true 都得显式配,而且目前 Packagist 上真正签名的包极少。
- 运行
composer show --security确认当前项目是否启用签名验证(输出含Signature verification: enabled才算) - 只对核心安全组件(如
paragonie/random_compat、web-token/jwt)优先启用,避免因签名缺失导致整个 install 失败 - 私有仓库(如 Satis)需额外配置 signing-key 或启用仓库级签名策略,不能只靠客户端开关
- 签名验证不替代 commit 锁定——它防的是包发布者被劫持,而 commit 锁定防的是分支被篡改或恶意小版本发布
真正难的不是写对那一行 dev-main#...,而是每次更新都重新核对哈希来源、每次 CI 都跑一次 git rev-parse、每次引入新包都人工确认其签名状态——这些动作没法自动化到 100%,但漏掉一次就可能让整条信任链失效。











