local_infile=off仅禁用客户端文件上传,不影响服务端文件操作;真正禁用服务端文件读写需设secure_file_priv=null并回收file权限。

local_infile=OFF 只禁客户端,不碰服务端文件读取
设 local_infile = OFF 后,LOAD DATA LOCAL INFILE 会失败,但 LOAD DATA INFILE、SELECT ... INTO OUTFILE 和 LOAD_FILE() 完全不受影响。这是最常被误以为“已禁用”的陷阱。
常见错误现象:mysql -e "SHOW VARIABLES LIKE 'local_infile';" 返回 OFF,但攻击者仍能执行 SELECT LOAD_FILE('/etc/passwd'); 成功读取系统文件。
-
local_infile是客户端连接级开关,只控制“从客户端机器上传文件”这一路径 - 它在
[mysqld]段配置生效(全局),也可用SET GLOBAL local_infile = OFF;动态关闭 - MySQL 8.0+ 默认为
OFF;旧版本常默认ON,需显式关闭
secure_file_priv=NULL 才真正堵死服务端文件操作
secure_file_priv = NULL 是禁用 LOAD DATA INFILE 和 SELECT ... INTO OUTFILE 的硬性开关,但必须配合回收 FILE 权限才完整。
参数差异:
-
secure_file_priv = ''(空字符串):危险!等价于允许任意路径读写 -
secure_file_priv = /var/lib/mysql-files/:仅限制路径,非禁止;只要文件在此目录下仍可读 -
secure_file_priv = NULL:强制拒绝所有服务端文件导入/导出操作,且无法绕过
注意:SET GLOBAL secure_file_priv = NULL 无效,必须写入 my.cnf 的 [mysqld] 段并重启 mysqld。
FILE 权限必须手动回收,否则 secure_file_priv=NULL 形同虚设
LOAD_FILE() 函数不走 secure_file_priv 校验,只检查用户是否拥有 FILE 权限和文件系统可读性。root 默认带此权限,日常运维几乎用不到。
实操建议:
- 查残留:
SELECT User, Host, File_priv FROM mysql.user WHERE File_priv = 'Y'; - 回收权限:
REVOKE FILE ON *.* FROM 'root'@'%';(别漏掉'root'@'localhost') - 验证效果:
SELECT LOAD_FILE('/etc/passwd');应返回NULL(无权限时静默失败),而非内容或明确报错
漏掉这步,攻击者拿到任意一个有 FILE 权限的账号,就能绕过 secure_file_priv 防御。
验证要看到两个不同错误才算真禁死
改完配置不是终点,必须用两条语句分别触发两类错误:
-
LOAD DATA INFILE '/etc/passwd' INTO TABLE t;→ 应报ERROR 1290 (HY000): The MySQL server is running with the --secure-file-priv option so it cannot execute this statement -
SELECT LOAD_FILE('/etc/passwd');→ 应返回NULL(权限不足)或ERROR 1045 (28000): Access denied
只看到第一个错误,说明 secure_file_priv 生效但 FILE 权限还在;只看到第二个错误,说明权限回收了但 secure_file_priv 没设对(比如设成了空字符串)。两者缺一不可。











