应立即检查并回收同时拥有 SUPER 和 FILE 权限的非 DBA 账号,确认 secure_file_priv 配置为有效路径或空字符串,禁用 phpMyAdmin 的 root 直连与空密码,杜绝 general_log 写入型提权。

查账号是否同时拥有 SUPER 和 FILE 权限
只要一个账号同时具备 SUPER 和 FILE 权限,攻击者在 SQL 注入得手后就能写 Webshell、读取 /etc/shadow 或 MySQL 配置文件,等同于获得服务器管理员权限。
别靠印象或文档判断,直接连上 MySQL 执行:
SELECT user, host, Super_priv, File_priv FROM mysql.user WHERE Super_priv = 'Y' OR File_priv = 'Y';
重点检查返回结果里有没有非 DBA 账号,比如 'appuser'@'%'、'report'@'10.20.%' 这类业务账号。确认后立刻回收:
REVOKE SUPER, FILE ON *.* FROM 'appuser'@'%';- 更彻底的做法是:
DROP USER 'appuser'@'%';,再按最小权限原则重建账号
验证 secure_file_priv 是否生效
secure_file_priv 是 FILE 权限的最后一道物理防线。即使误留了 FILE 权限,只要它设对了,危害就被锁死。
立即学习“PHP免费学习笔记(深入)”;
先查当前值:
SELECT @@secure_file_priv;
返回值必须是明确路径(如 /var/tmp/)或空字符串 ''(MySQL 8.0+ 支持,表示禁用所有 LOAD_FILE/INTO OUTFILE),不能是 NULL。
如果返回 NULL,说明该参数未配置,风险极高;如果设成了 /、/tmp 或 /var/www/html 这类开放路径,等于没设。
正确配置方式(在 my.cnf 的 [mysqld] 段下):
- 严格模式(推荐):
secure_file_priv = "" - 受限模式:
secure_file_priv = "/var/tmp/",并确保该目录属主为mysql:mysql、无执行位(chmod 755 /var/tmp即可,不要777)
改完必须重启 MySQL 生效,且不能只靠 SET GLOBAL 临时修改——该变量是只读的。
禁止用 root 或空密码登录 phpMyAdmin
phpMyAdmin 本身不校验用户权限粒度,它只是把你的 SQL 请求原样发给 MySQL。所以你在界面上看到“没有权限”的提示,往往不是 phpMyAdmin 拦的,而是 MySQL 拒绝执行了。但一旦你用 root 登录,就绕过了所有前端限制。
常见错误操作包括:
- 用
root用户 + 弱口令(甚至空密码)暴露在公网 - 在
config.inc.php中硬编码$cfg['Servers'][$i]['password'] = ''; - 开启
$cfg['Servers'][$i]['AllowNoPassword'] = true;(默认为 false,切勿打开)
正确做法:
- 删除所有非必要
root账号的远程访问权限:DROP USER 'root'@'%'; - 日常运维使用独立账号,只授予
SELECT, INSERT, UPDATE, DELETE等必要权限,绝对不给SUPER、FILE、GRANT OPTION - 强制通过 HTTPS 访问 phpMyAdmin,并在 Web 服务器层加 IP 白名单或 HTTP Basic Auth
警惕日志写入型提权(general_log)
即使没有 INTO OUTFILE 权限,攻击者仍可能通过操纵 MySQL 日志功能写入一句话木马,前提是账号有 SUPER 权限(因为 general_log_file 是全局变量)。
典型攻击链:
SET GLOBAL general_log = 'ON';SET GLOBAL general_log_file = '/var/www/html/shell.php';SELECT '<?php system($_GET["cmd"]); ?>';SET GLOBAL general_log = 'OFF';
防范要点:
- 禁用
SUPER权限是最根本的解决方式——普通业务账号完全不需要它 - 若必须保留(如监控账号),则必须同步禁用
FILE,并确保secure_file_priv不为空 - 定期检查
SHOW VARIABLES LIKE 'general_log%';,发现异常开启立即告警
最易被忽略的是:很多团队以为“只给了 SELECT 就安全”,却忘了 LOAD_FILE() 和 SELECT ... INTO OUTFILE 都属于 SELECT 语义范畴,不需要额外权限。真正的边界不在 phpMyAdmin,而在 MySQL 账号本身的权限设计。



















