生产环境不能只靠 composer install 防后门,因其不校验包来源与内容完整性,仅依赖可能被篡改的 composer.lock 中 dist.shasum 和 HTTP 下载链路,且自定义源、开发依赖、非权威类加载等均扩大攻击面。

生产环境为什么不能只靠 composer install 防后门?
因为 composer install 本身不校验包来源和内容完整性——它只按 composer.lock 里的 dist.url 和 dist.shasum 下载并比对哈希,但前提是这些字段真实有效、未被篡改,且下载链路未被劫持。
常见错误现象:composer.lock 被提交时 dist.shasum 为空或长度不对(非64字符),或用了 HTTP 源导致中间人替换 dist 包;又或者 repositories 块存在,让 Composer 直接绕过 Packagist 官方索引,从不可信私源拉包。
- 检查每个包的
dist.shasum:打开composer.lock,搜索"shasum",确认值为 64 字符十六进制字符串(如"a1b2c3..."),不是null、空字符串或 40 字符(SHA-1) - 禁用所有自定义源:删掉
composer.json中整个repositories块;运行composer config --global repo.packagist false后显式重设官方源 - 强制 HTTPS 元数据 + 签名验证:确保
secure-http=true(默认),并执行composer config -g security.signature-verification true
--no-dev 和 --classmap-authoritative 不只是性能开关
它们是攻击面收缩的关键配置。开发依赖里常含调试工具、代码生成器等高权限插件,一旦被注入恶意逻辑,composer install 执行时就会自动触发;而 --classmap-authoritative 关闭动态类加载,防止攻击者通过伪造文件路径绕过 autoloader 限制。
-
--no-dev必须加:跳过require-dev和autoload-dev,避免加载phpunit、phpstan等含 exec/hook 的包 -
--classmap-authoritative必须加:生成完整 classmap 并禁用 PSR-4/PSR-0 fallback,使vendor/autoload.php中'classmap-authoritative' => true生效 - 不要加
--ignore-platform-reqs:它会跳过 PHP 版本、扩展检查,可能让不兼容的恶意包“降级”绕过校验
CI 构建阶段必须做三件事,缺一不可
生产机上根本不该有 composer 命令——所有校验、安装、清理都得在 CI 完成。否则部署时再跑 composer install,等于把校验权交给了运行时环境,而那里很可能没装 GPG、没开 TLS 校验、甚至被植入了 hook 插件。
- 构建前先校验锁文件:运行
composer validate --strict,失败则中断;再用git diff --quiet composer.lock确保未被本地修改 - 构建中用完整参数安装:
composer install --no-dev --optimize-autoloader --classmap-authoritative --no-interaction --prefer-dist - 构建后立即清理敏感残留:
rm -rf vendor/bin/ vendor/**/tests/ vendor/**/.git vendor/composer/installed.json
上线后还能手动验证 vendor 是否被篡改?
能,但必须用 composer verify-checksums,而不是靠文件时间戳或目录大小。这个命令会重新读取 composer.lock 中每个包的 dist.shasum,并实时计算已安装文件的 SHA-256,逐字节比对。
- 先确保
COMPOSER_NO_INTERACTION=1,避免卡在确认提示 - 运行
composer verify-checksums --strict:遇到任何哈希不匹配、缺失文件或 shasum 长度异常,都会报错退出 - 注意:该命令不校验 source 类型包(如 Git clone),只校验 dist 类型;若项目混用 source,需额外用
git status -s vendor/辅助检查
真正危险的不是某次 update 引入了后门,而是 lock 文件本身被悄悄替换成一个“看起来合法、但 dist.shasum 全部伪造”的版本——所以每次构建前的 composer validate --strict 和每次上线后的 verify-checksums --strict 必须成为硬性步骤,不能靠人眼扫一眼 composer.lock 就算完事。











