万能密码能绕过登录验证,是因为应用层未使用预处理语句,直接将用户输入拼接进SQL字符串,使攻击者可通过' OR '1'='1' --等构造篡改查询逻辑,令WHERE条件恒真,从而绕过密码校验。

为什么万能密码能绕过登录验证
万能密码(如 ' OR '1'='1' --)之所以有效,是因为应用层直接把用户输入拼进SQL字符串,导致数据库执行了被篡改的逻辑。MySQL本身不会拦截这种语句——它只负责执行你给的SQL。真正起作用的是开发时没用预处理、也没做输入校验,让攻击者能控制查询结构。
禁用 LOAD DATA 和文件类操作必须设 secure_file_priv
攻击者常通过 LOAD DATA INFILE 或 SELECT ... INTO OUTFILE 读取服务器文件(如 /etc/passwd)或写入Webshell。MySQL不提供“开关式”禁用命令,而是靠配置限制路径:
-
secure_file_priv = /var/lib/mysql-files/是唯一有效方式:它强制所有文件操作只能在该目录下进行;设为NULL则完全禁用 - 不要留空或设为
/,否则等于开放整个文件系统 - 修改后需重启MySQL,且该值在运行时不可动态更改:
SET GLOBAL secure_file_priv = ...会报错 - 检查是否生效:
SELECT @@secure_file_priv;返回NULL或具体路径才算成功
禁用高危系统函数不能靠 DROP FUNCTION,得从权限和配置双控
像 sys_exec、load_file、updatexml 这类函数不是MySQL默认内置的(除 load_file 外),但一旦被手动安装或启用,就可能成为注入出口。防御重点不在“删函数”,而在阻断调用链:
- 业务账号必须剔除
FILE权限:REVOKE FILE ON *.* FROM 'app_user'@'%';,否则load_file()可直接读敏感文件 - 禁用自定义函数加载:在
my.cnf中添加local_infile = OFF(防止客户端上传)和disabled_storage_engines = "MyISAM,ARCHIVE"(减少攻击面) -
updatexml()等报错注入依赖错误回显,所以生产环境务必关闭sql_mode中的宽松模式,启用STRICT_TRANS_TABLES,并确保 Web 层不输出 MySQL 错误详情
仅靠配置不够,万能密码防护必须落在代码层
再严的MySQL配置也拦不住一个拼接SQL的PHP脚本。真正卡住万能密码的,是应用层对登录逻辑的处理方式:
- 登录查询必须用预处理:
$stmt = $pdo->prepare("SELECT id, pass_hash FROM users WHERE username = ? AND status = 'active'");,两个参数都走占位符,连单引号都进不了SQL结构 - 用户名字段建议加长度限制(如
VARCHAR(32))和格式校验(只允许字母数字下划线),避免超长payload触发其他漏洞 - 别信“过滤单引号就行”——
addslashes()和正则替换在多字节编码、宽字符场景下极易绕过,纯属心理安慰 - 如果非要用动态表名(极少见),只能走白名单映射,绝不能用用户输入直拼:
$table = in_array($input, ['orders_2024', 'orders_2025']) ? $input : 'orders_2024';
最常被忽略的一点:secure_file_priv 设了 ≠ 文件操作就安全了,因为攻击者可能先通过SQL注入拿到数据库账号密码,再用本地客户端直连绕过Web层限制。防万能密码,本质是防住第一处拼接点,而不是等它爆出来再补洞。











