必须同时禁用FILE权限并设secure_file_priv为NULL或指定路径,缺一不可;仅设NULL可彻底禁止SELECT INTO OUTFILE和LOAD DATA INFILE,但需配合REVOKE FILE ON .才能防绕过,MySQL 8.0.17+才支持NULL值,5.7须设不存在路径并撤权限。

必须同时禁用 MySQL 的 FILE 权限 + 限制 secure_file_priv,缺一不可。只改一个,攻击者大概率仍能写马。
检查当前 secure_file_priv 是否已放开
登录 MySQL 命令行,执行:
SHOW VARIABLES LIKE 'secure_file_priv';
结果有三种典型情况:
-
NULL:禁止所有文件读写(最安全,但旧应用可能报错) -
/tmp/或其他具体路径:仅允许在该目录下读写(推荐) - 空字符串(
''):等效于“任意路径可读写”,MySQL 5.7+ 允许,8.0+ 已不支持——但很多一键包(如 PHPStudy、XAMPP)默认设为空,这是高危信号
若看到空字符串,立刻修改配置文件(my.cnf 或 my.ini),在 [mysqld] 段下加:
secure_file_priv = /var/lib/mysql-files/
注意:/var/lib/mysql-files/ 必须存在、属主为 mysql、权限为 750,且不能挂载在 Web 可访问路径下(比如不能是 /var/www/html/ 的子目录)。
确认数据库账号是否还持有 FILE 权限
FILE 权限是 INTO OUTFILE 的执行前提,哪怕 secure_file_priv 设对了,只要账号还有这个权限,就可能被用于写文件到受限目录(比如写进 /var/lib/mysql-files/shell.php,再配合其他漏洞读取或触发)。
执行以下命令检查目标账号(例如 'app_user'@'localhost'):
SHOW GRANTS FOR 'app_user'@'localhost';
如果输出中含 FILE,立即回收:
使用ydata-profiling(前身为pandas-profiling)生成全面的数据质量报告,包含相关性分析、缺失值模式和基数检测。导出交互式HTML仪表板和JSON摘要。
REVOKE FILE ON *.* FROM 'app_user'@'localhost';
⚠️ 注意:REVOKE 不报错也不保证生效。必须紧接着再跑一次 SHOW GRANTS,逐行确认 FILE 确实消失了。权限可能来自角色继承,所以也要查:
SELECT * FROM mysql.role_edges WHERE TO_HOST = 'localhost' AND TO_USER = 'app_user';
phpMyAdmin 配置要同步切断导出入口
phpMyAdmin 本身不控制 INTO OUTFILE,但它提供了图形化界面发起该操作的通道。即使后端 MySQL 已禁用,前端若留着导出按钮,用户仍可能误点或被诱导执行恶意 SQL。
编辑 phpMyAdmin 的 config.inc.php,确保以下几项清空或关闭:
-
$cfg['SaveDir'] = '';:禁用「导出到服务器」功能(否则可能把 CSV/SQL 导出成.php后缀存到 Web 目录) -
$cfg['UploadDir'] = '';:禁用「从服务器导入」功能(防止上传恶意 SQL 文件) -
$cfg['ShowSQL'] = false;:隐藏 SQL 执行页的系统变量和导入按钮
另外,检查 Web 服务器对上传目录的实际权限:若 $cfg['UploadDir'] 指向了 /var/www/html/uploads/,必须确保该目录禁用 PHP 解析(Nginx 加 location ~ \.php$ { deny all; },Apache 用 <FilesMatch "\.php$"> Deny from all </FilesMatch>)。
验证是否真禁掉了写入能力
别信配置改完就完事。必须人工验证:
用目标账号登录 MySQL 命令行,执行:
SELECT 'test' INTO OUTFILE '/tmp/test.txt';
预期返回两种之一:
-
ERROR 1290 (HY000): The MySQL server is running with the --secure-file-priv option...(说明secure_file_priv生效) -
ERROR 1045 (28000): Access denied for user ... using password: YES(说明FILE权限已回收)
如果成功写入文件,说明至少一个环节没堵住——常见漏点是:Docker 容器内 MySQL 配置未 reload、my.cnf 被多个配置文件覆盖、或账号权限通过角色间接继承未清理。

















