禁用多语句执行能阻断堆叠注入,因其依赖mysqli_multi_query等函数显式支持分号分隔的多语句执行,而mysqli_query等单语句函数遇分号直接报错;WAF过滤分号可被编码绕过,唯有驱动层禁用才从根本上消除执行基础。

MySQL 默认不允许多语句执行,但只要用了 mysqli_multi_query 或启用了 MYSQLI_CLIENT_MULTI_STATEMENTS,堆叠查询就可能生效 —— 所以禁用它比“过滤分号”更直接有效。
为什么禁用多语句执行能阻断堆叠注入
堆叠注入不是靠“绕过过滤”起效的,而是依赖底层数据库驱动明确支持并执行多条语句。MySQLi 和 PDO 的行为差异很关键:
-
mysqli_query()严格只执行一条语句,遇到分号会直接报错MySQLi SQL syntax error -
mysqli_multi_query()是唯一默认允许堆叠的 MySQLi 函数,且不校验语句合法性,第二条起全交由数据库执行 - PDO 默认禁用多语句(
PDO::ATTR_EMULATE_PREPARES = true时甚至会把分号当字符串),但若显式开启PDO::MYSQL_ATTR_MULTI_STATEMENTS = true,风险立刻回归
在 PHP 中关闭多语句执行的具体配置
重点不是改 SQL 写法,而是收紧连接初始化时的客户端能力:
- MySQLi 连接时,**不要传
MYSQLI_CLIENT_MULTI_STATEMENTS标志**:$mysqli = new mysqli($host, $user, $pass, $db, $port);(不带第 6 个参数) - PDO 连接时,**显式关闭多语句支持**:
$pdo = new PDO($dsn, $user, $pass, [PDO::MYSQL_ATTR_MULTI_STATEMENTS => false]); - 如果使用 Laravel / Symfony 等框架,检查数据库配置中是否含
options => [PDO::MYSQL_ATTR_MULTI_STATEMENTS => true],删掉它
禁用后仍需注意的兼容性陷阱
有些旧业务代码会依赖 mysqli_multi_query 做批量 DDL(如建表+插入),禁用后这类逻辑会直接失败,而不是静默降级:
- 错误现象:
mysqli_multi_query(): Unable to execute multiple queries或 PDO 报SQLSTATE[HY000]: General error: 2014 Cannot execute queries while other unbuffered queries are active - 真实场景中,这类调用往往出现在安装脚本、迁移工具或 CMS 初始化流程里,不是运行时高频路径
- 替代方案是拆成多次
mysqli_query()调用,或用事务包裹单条语句(BEGIN; ... ; COMMIT;),而非依赖堆叠
真正容易被忽略的是:WAF 或中间件层对分号的拦截,无法替代驱动层的禁用。因为攻击者可编码绕过(如 %3B)、混淆空格、或直接走非 HTTP 接口(如 CLI 脚本直连 DB)。只有在连接建立那一刻就掐断多语句能力,才能让堆叠注入从“语法可行”变成“根本不可达”。


















