composer 必须配置 https-proxy 而非仅 http-proxy,因包元数据和 dist 文件均走 https,需 connect 隧道;漏配或错误配置会导致中间人篡改响应体,引发 content-length mismatch 或证书错误。

为什么只配 http-proxy 会触发报文篡改
Composer 对 HTTP 和 HTTPS 请求走完全独立的代理通道,http-proxy 只影响纯 HTTP 请求(几乎不用),而所有包元数据和 dist 文件都走 HTTPS,必须靠 https-proxy 建立 CONNECT 隧道。漏配或填错 https-proxy,请求就直连出去,经过企业中间人代理时会被解密、重签、再加密——这个过程可能修改响应体(比如注入 JS、替换 Content-Length、截断大文件),最终触发 Content-Length mismatch 或 SSL certificate problem。
-
https-proxy的值必须是http://开头,哪怕代理本身监听 TLS 端口(这是 Composer 硬性约定) - 填成
https://127.0.0.1:8080或不带协议头,会导致静默 fallback 到直连,无错误提示但实际被篡改 - 密码含
@、/、:必须 URL 编码,否则解析失败,等效于未配置 - Windows 下路径权限不足(如
%APPDATA%\Composer\config.json不可写)也会导致配置未生效
如何验证是否遭遇中间人篡改
别猜,直接比对原始响应和 Composer 收到的内容。最简单的方式是用 curl 模拟相同请求,看响应头和 body 是否一致:
curl -vI https://mirrors.aliyun.com/composer/packages.json
如果 curl 报 certificate verify failed 但浏览器能打开,基本确定是 TLS 中间人;如果 curl 正常但 composer install -vvv 日志里出现 received 123456 bytes out of the expected 789012,说明响应体被截断或重写。
- 运行
composer diagnose,关注是否报curl error 60(证书校验失败)或curl error 7(连接拒绝) - 加
-vvv参数后观察日志中实际发起的 URL 和 Host 头,确认没 fallback 到packagist.org - 检查
composer config -g cafile是否指向公司根证书(PEM 格式),而不是设成/dev/null
强制可信链:禁用 fallback + 锁定镜像域名
即使代理层不可信,也能从 Composer 配置源头切断篡改路径。关键不是“防住”,而是“不让它有机会发生”——所有请求必须明确落在白名单域名上,且不允许降级。
- 全局启用 HTTPS 强制:
composer config -g secure-http true,拒绝任何http://镜像 - 禁用 packagist.org fallback:在项目
composer.json顶层加"packagist.org": false(注意不是字符串"false") - 镜像 URL 必须带
type=composer和结尾/,例如https://mirrors.aliyun.com/composer/,少斜杠会拼出错误路径 - CI/CD 脚本中加入域名白名单检查:
composer config --list | grep -E "mirrors\.aliyun\.com|mirrors\.tuna\.tsinghua\.edu\.cn",失败则exit 1
pre-file-download 是最后防线,但不能替代配置管控
pre-file-download 事件确实能在下载前拦截并重写 URL,甚至注入 Authorization 头,但它只作用于 dist 文件(ZIP/TAR),不覆盖元数据请求(packages.json)。也就是说,一旦 packages.json 已被篡改(比如返回了恶意 dist URL),插件根本来不及干预。
- 该事件适合做缓存代理、Token 注入、日志审计,不适合做安全兜底
- 不要依赖它来“修复”被污染的镜像源,那等于在洪水入口装滤网
- 真正要防的是
repo.packagist配置被动态覆盖,所以必须禁用项目级repositories字段,统一用全局配置 - 若必须支持私有源,用
"type": "package"显式声明每个包的dist.url和dist.shasum,跳过镜像同步环节
最危险的不是网络被篡改,而是你误以为 Composer 有容错能力——它没有重试降级、没有响应体校验、不缓存失败请求,所有防护都得卡在配置解析那一刻。漏掉一个斜杠、少配一个字段、多信一次 http-proxy,就可能让整个构建链路暴露在中间人之下。











