堆叠查询允许一次请求执行多条SQL语句,可执行DROP、INSERT、UPDATE等写操作,危害远超普通注入。其根源在于后端驱动支持多语句配置(如mysqli_multi_query、PDO多语句选项),输入过滤和WAF难以有效拦截。唯一防御是连接时禁用多语句能力,但禁用后可能导致旧逻辑崩溃等兼容性问题。
堆叠查询为何在某些SQL环境中危害极大?
时间:2026-06-17
浏览:180
文章目录
在SQL注入的诸多变种中,堆叠查询(Stacked Queries)始终是威胁性极高的一种攻击方式。普通SQL注入通常只能读取数据,而堆叠查询允许一次请求中执行多条SQL语句,包括删除表、插入数据、修改权限等,几乎可以完成任意数据库操作。只要后端驱动支持多语句执行,这种攻击就很难通过简单的输入过滤彻底防御。

堆叠查询能执行 DROP/INSERT/UPDATE 等写操作
普通的SQL注入(例如 UNION 注入或盲注)通常只能读取数据,而堆叠查询则允许在一次请求中同时执行多条语句。举例来说,攻击者可以传入 '; DROP TABLE users; -- 或 '; INSERT INTO admins VALUES ('hacker', 'pwd'); -- 这样的输入。只要后端使用了 mysqli_multi_query() 或者显式启用了 PDO::MYSQL_ATTR_MULTI_STATEMENTS = true 等多语句驱动配置,数据库就会按顺序依次执行——先查询、再删除、再插入,完全不受应用层逻辑的约束。
MySQL 默认不启用多语句,但 PHP 驱动常被误配
MySQL 服务端本身默认只接受单条语句,真正打开堆叠攻击大门的是客户端驱动的行为。具体区别如下:
mysqli_query()遇到分号会直接报错:MySQLi SQL syntax errormysqli_multi_query()是唯一默认允许堆叠的函数,且不会校验第二条语句的合法性- PDO 默认禁用多语句,但若显式设置
PDO::MYSQL_ATTR_MULTI_STATEMENTS => true,风险立刻回归
许多旧项目在初始化 PDO 时没有关闭这个标志,或者直接使用 mysqli_multi_query() 执行批量操作,结果导致原本只能读取数据的注入入口升级为可写可删的严重漏洞。
WAF 和输入过滤很难有效阻止堆叠查询。分号(;)看似容易拦截,但攻击者拥有大量绕过方式:使用 URL 编码 %3B 替代 ;、加入空格混淆写成 ;/**/DROP/**/TABLE,甚至还可以通过非 HTTP 接口直接连接数据库(例如 CLI 脚本、定时任务、管理后台 API),这些场景下 WAF 根本无法覆盖。真正有效的防御措施只有一条:在建立数据库连接时就彻底禁止驱动执行多语句的能力——不是过滤用户输入,而是让驱动根本不具备执行多条语句的权限。
修复后容易忽略的兼容性问题
禁用 mysqli_multi_query() 或关闭 PDO::MYSQL_ATTR_MULTI_STATEMENTS 之后,部分旧代码会直接崩溃,而不是静默降级。例如在安装脚本中使用堆叠查询建表并插入初始数据,会触发错误:Cannot execute queries while other unbuffered queries are active。再比如某些 CMS 初始化流程依赖一次发送多条 DDL 语句来建库,失败后日志中可能只记录一句“DB init failed”,而不提示具体原因。这类调用往往不在主业务链路上,排查时容易被误认为是环境问题而忽略,但实际上正是禁用堆叠查询后必然出现的结果。
实用工具推荐
绿化、压缩、噪点和虚拟水印,自由调节做旧程度。
选择画质和输出格式,预览压缩前后的大小。