预处理语句仅防拼接注入,但无法阻止在ORDER BY等非参数化位置的注入及后续提权;真正决定提权成败的是数据库账号是否拥有FILE、GRANT OPTION、SUPER等高危权限。

仅靠过滤输入或使用预处理语句,无法阻止SQL注入后的权限提升;真正起决定作用的是数据库账号本身有没有FILE、GRANT OPTION、SUPER等高危权限。
为什么预处理语句挡不住提权
预处理语句(如mysqli_prepare或PDO::prepare)能防止拼接式注入,但对以下场景完全无效:
- 注入点出现在
ORDER BY、GROUP BY、LIMIT等非参数化位置时,仍可执行SELECT ... INTO OUTFILE或LOAD DATA INFILE - 应用使用
root或sa连接,且未禁用FILE权限 → 一旦注入成功,攻击者可读取/etc/passwd或写入Web目录生成木马 - 账号拥有
GRANT OPTION→ 注入后可直接执行GRANT SUPER ON *.* TO 'attacker'@'%'完成提权
必须禁用的三个高危权限
用业务账号登录后,立即执行SHOW GRANTS确认是否残留危险权限:
-
FILE:允许读写服务器文件系统。云数据库(如阿里云RDS)虽默认关闭secure_file_priv,但只要账号有FILE权限,仍可能绕过限制 -
GRANT OPTION:允许该账号给其他用户授予权限。哪怕只给了SELECT,它也能把自己升级成SUPER -
SUPER或SYSTEM_VARIABLES_ADMIN(MySQL 8.0+):可修改全局变量(如log_bin_trust_function_creators=1),为UDF提权铺路
执行禁用命令示例(需用更高权限账号操作):REVOKE FILE, GRANT OPTION, SUPER ON *.* FROM 'app_user_order'@'%';
PostgreSQL里容易被忽略的public schema陷阱
PostgreSQL默认把所有新用户加入public schema,且该schema对所有用户可读写。这意味着:
- 注入点若涉及
CREATE TEMP TABLE或CREATE FUNCTION,攻击者可创建恶意函数并触发执行 - 即使没
CREATE权限,在public下建临时表不校验权限,可能覆盖已有视图或触发器 - 修复方式不是删掉
public,而是执行:REVOKE CREATE ON SCHEMA public FROM PUBLIC;,再显式授予业务所需最小schema权限
权限最小化的实操检查清单
每次上线新模块前,用该模块专用账号做三件事:
- 执行
SHOW GRANTS FOR 'app_user_report'@'%';,确认输出中不含FILE、GRANT OPTION、SUPER、CREATE、DROP、ALTER、EXECUTE - 尝试执行
SELECT LOAD_FILE('/etc/passwd');,应返回NULL或报错ERROR 1290 (HY000),而非内容 - 在MySQL中执行
SELECT @@secure_file_priv;,确保值不是空字符串或/;在PostgreSQL中检查\du++与\dp,确认无意外继承的CREATEROLE或CREATEDB
权限不是配一次就完事——每次数据库账号变更、迁移、或接入新中间件(比如DMS、DataGrip),都得重新验证SHOW GRANTS输出。很多提权事故,就发生在运维顺手用root账号导出再导入数据之后。











