composer本身不分析代码逻辑,仅通过composer audit比对composer.lock中精确版本与friendsofphp安全数据库的已知cve,无法识别sql注入等逻辑漏洞,必须依赖psalm污点分析、semgrep规则扫描等外部sast工具。

Composer 本身不提供 SQL 注入静态分析能力,必须配合外部安全扫描工具(如 PHPStan、Psalm、Semgrep 或专用 SAST 工具)才能在代码层面识别潜在 SQL 注入风险。
为什么 composer install 或 composer update 不会发现 SQL 注入漏洞
Composer 只负责依赖下载、自动加载注册和版本解析,它不解析 PHP 源码逻辑,也不检查 query()、execute() 或字符串拼接行为。即使你用了存在高危 SQL 拼接的包(比如过时的 medoo 或手写 DAO),Composer 也只会安静地装上它。
常见错误现象:composer audit 返回 “No security advisories found” 就以为项目安全——这仅表示已知 CVE 数据库中无匹配条目,不代表代码里没 $sql = "SELECT * FROM user WHERE id = " . $_GET['id'] 这类硬编码拼接。
- Composer 的
audit命令只查 packagist.org 的安全通告(security-advisories),不分析你的业务代码 - 它无法识别自定义 SQL 构建逻辑、ORM 误用(如 Laravel 的
whereRaw()未过滤)、或第三方包中未被上报的逻辑缺陷 - 依赖树中某个子依赖含漏洞,但主项目未调用对应函数?Composer audit 仍可能漏报
用 Semgrep 快速扫描项目内高危 SQL 拼接模式
Semgrep 轻量、规则开源、支持自定义,适合嵌入 CI 或本地 pre-commit 扫描。它能直接匹配 PHP 中危险的字符串拼接 + SQL 执行函数组合。
示例规则(保存为 sql-injection-php.yaml):
rules:
- id: php-sql-injection-string-concat
patterns:
- pattern: $DB->query("...$X...")
- pattern-inside: |
<?php ...
?>
message: Dangerous string interpolation in SQL query. Use prepared statements.
languages: [php]
severity: ERROR
执行扫描:
semgrep --config=sql-injection-php.yaml --no-git-ignore ./src
- 重点覆盖:
mysql_query()、mysqli::query()、PDO::exec()、PDO::query()、DB::select()(Laravel)、->whereRaw()等上下文 - 注意绕过:攻击者可能用
str_replace()、addslashes()伪装“已过滤”,Semgrep 规则需额外排除白名单函数调用链,否则误报率高 - 不推荐用正则全局扫
"SELECT"或"INSERT"字符串——太泛,噪音大
结合 Psalm 或 PHPStan 的扩展插件做类型流分析
Psalm 的 taint-checking 模式可追踪用户输入(如 $_GET、$request->input())是否未经净化就流入 SQL 执行函数。比语法匹配更准,但需要项目有基础类型注解或 PHP 8.0+ 类型声明。
启用方式(psalm.xml):
<psalm><taintanalysis></taintanalysis><plugins><pluginclass class="Psalm\Plugin\TaintAnalysis\Plugin"></pluginclass></plugins></psalm>
它能捕获这类链路:$_GET['id'] → $id → "SELECT * FROM users WHERE id = $id" → $pdo->query($sql)。
- 必须开启
--taint-analysis参数运行:psalm --taint-analysis - 对动态调用(如
call_user_func([$db, 'query'], $sql))识别弱,需补全 stubs 或 suppress 特定行 - 与 Composer 无关,但建议在
composer install后立即跑一次,确保新引入的包没带污染传播路径
CI 中串联 Composer + 扫描工具的最小可行流程
不要把安全扫描当成“发布前手动点一下”的事。应在每次 composer update 后自动触发语义层检查,尤其当升级了 ORM、DBAL 或 HTTP 客户端类库时。
GitHub Actions 示例片段(关键步骤):
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: composer install --no-interaction
- name: Run Semgrep
uses: returntocorp/semgrep-action@v2
with:
config: p/php
- name: Run Psalm taint check
run: vendor/bin/psalm --taint-analysis --no-progress
容易踩的坑:
- 忘记在 CI 中安装 Semgrep 或 Psalm:用
curl -sS https://semgrep.dev/install | sh或composer require --dev vimeo/psalm - Psalm 报错阻断 CI?先用
--output-format=gitlab或--report=ci.json集成,别直接 fail-fast - 开发机和 CI 环境 PHP 版本不一致,导致 Psalm 类型推导结果不同——锁定
platform配置项
真正难的不是加工具,是持续维护规则和接受“误报也要人工确认”。比如一个 whereRaw() 确实用了 DB::raw() 和绑定参数,但 Psalm 仍报警——这时得加 // @psalm-taint-untrusted 注释,而不是关掉检查。











