composer outdated 查不出 typosquatting 包,因它仅比对 composer.json 中显式声明的包名,不扫描名称相似但未声明的包;需通过解析 composer.lock 或依赖树并结合编辑距离与关键词规则主动检测。

composer outdated 为什么查不出 typosquatting 包?
它只比对 composer.json 里已声明的包名,根本不会去扫描“名字像但没写进去”的包。比如你写了 monolog/monolog,它不会主动检查 monolog/monolg 或 monolog/monologg 是否被间接引入——除非那个错拼包真被某个合法依赖作为子依赖拉进来了,而这时它已经混进 composer.lock,outdated 还是看不见,因为没在 require 列表里。
怎么主动发现疑似 typosquatting 的包?
靠人工肉眼扫 composer.lock 不现实。真实可行的是用 composer show --tree 输出依赖树后做字符串相似度筛查:
- 提取所有包名(格式为
vendor/name),排除你自己项目和已知白名单(如php,ext-*) - 对每个包名,计算与主流包的编辑距离(Levenshtein distance),比如
laravel/framework和laravel/framwork距离为 1,guzzlehttp/guzzle和guzzlhttp/guzzle距离为 2 - 设定阈值(建议 ≤2),再结合常见投毒模式过滤:含
admin、root、dev、test、debug等词的包名优先告警 - 别忘了检查
repositories字段——很多 typosquatting 包来自非 Packagist 源,composer config repositories必须清点
CI 中如何自动拦截错拼包?
不能等上线才发现。在 CI 流水线里加一道校验脚本,核心逻辑是:
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
#!/bin/bash
# 提取 lock 文件中所有 vendor/name 格式包名(跳过 root package)
jq -r '.packages[] | select(.name != null) | .name' composer.lock 2>/dev/null |
while read pkg; do
# 检查是否匹配已知错拼规则(可维护一个本地规则集)
if echo "$pkg" | grep -Eq '^(laravel|monolog|guzzle|symfony|doctrine)/[a-z]*([aeiou]{0,2})?[a-z]*$'; then
# 进一步用 levenshtein 工具或 PHP 脚本算相似度
php -r "echo levenshtein('$pkg', 'laravel/framework') . "\n";" 2>/dev/null |
awk '$1 <= 2 { print "TYPOSQUATTING ALERT: $pkg -> laravel/framework"; exit 1 }'
fi
done注意:这个检查必须在 composer install 之后、代码构建之前运行;否则恶意包可能已解压并执行了 post-install-cmd。
为什么光靠包名黑名单会失效?
攻击者发新包根本不走老路。今天封了 laravel-debugbar,明天就上 laravel-debbugbar 或 laravel-debug-barr。真正有效的防线是:
- 强制所有包启用签名:
"require-signature": true,未签名的错拼包直接被 Composer 拒绝安装 - 禁用非官方仓库:
composer config --unset repos.packagist.org后再显式设置repos.packagist.org为{"type": "composer", "url": "https://packagist.org"} - 把
composer.lock提交进 Git,并开启 CI 对 lock 文件的 SHA256 校验——任何未经审查的依赖变更都会被拦住
最易被忽略的是:typosquatting 往往不靠单个包作恶,而是通过“正常包 A → 错拼包 B → 恶意包 C”三级跳链引入,所以必须对整个依赖树做横向相似度扫描,而不是只盯着顶层 require。

















