必须服务端和客户端双侧禁用并实测:SELECT @@local_infile返回0,且LOAD DATA LOCAL INFILE '/etc/passwd'报ERROR 1148;配置须写入[mysqld]段并重启,同时禁用secure_file_priv和FILE权限。

只关服务端 local_infile = OFF 不够,必须服务端和客户端同时禁用,且全部实测验证通过才算真正生效。
怎么确认 local_infile 真被禁用了?
不能只信 SHOW VARIABLES LIKE 'local_infile' 返回 OFF,也不能只看配置文件写了没。必须做两件事:
- 执行
SELECT @@local_infile;—— 必须返回0(不是字符串'OFF') - 用普通账号连接后运行
LOAD DATA LOCAL INFILE '/etc/passwd' INTO TABLE t;—— 必须报错ERROR 1148 (42000) - 如果报
ERROR 2068 (HY000),说明客户端和服务端都拦住了;如果报权限错误或静默失败,说明某一层漏了
服务端禁用必须写对位置并重启
local_infile = OFF 只在 [mysqld] 段下才有效,写进 [mysql] 或 [client] 段等于白配:
- 常见路径:CentOS 是
/etc/my.cnf,Ubuntu/Debian 多是/etc/mysql/mysql.conf.d/mysqld.cnf - Docker 容器里要确认挂载的配置是否覆盖了镜像内默认配置,且启动命令没用
--local-infile覆盖它 - 改完必须
sudo systemctl restart mysql(或mariadb),reload不生效
客户端连接时必须显式关闭 local_infile
服务端关了,客户端还开着,SQL 注入就能诱使应用代码读取本地敏感文件(比如 ~/.my.cnf):
- MySQL CLI:
mysql -u user -p --local-infile=0,别依赖~/.my.cnf里的[client]段 —— 某些版本会忽略 - PyMySQL:
pymysql.connect(..., local_infile=False)(注意是布尔值False,不是字符串) - PHP mysqli:
mysqli_options($conn, MYSQLI_OPT_LOCAL_INFILE, false),且必须在mysqli_real_connect()前调用 - JDBC URL:
&allowLoadLocalInfile=false,确保没被其他参数覆盖
别漏掉 secure_file_priv 和 FILE 权限
local_infile = OFF 只防 LOAD DATA LOCAL INFILE,不防服务端自己读文件:
- 加
secure_file_priv = NULL到[mysqld]段并重启,再查SELECT @@secure_file_priv;应返回NULL - 执行
REVOKE FILE ON *.* FROM 'user'@'host';,特别检查root账号:SELECT User,Host,File_priv FROM mysql.user WHERE File_priv='Y'; - 验证
LOAD DATA INFILE '/etc/passwd' INTO TABLE t;应报ERROR 1290
最常被忽略的是:以为改了配置就万事大吉,结果没验证、没覆盖所有客户端类型、也没清理 FILE 权限。攻击者只要找到一个开着 local_infile 的连接点,就能把数据库服务器变成跳板,读取开发机或 CI 机器上的密钥文件。











