必须同时禁用服务端local_infile=OFF(写入my.cnf[mysqld]段并重启)、客户端显式禁用(如PyMySQL设local_infile=False)、回收FILE权限并设secure_file_priv=NULL,缺一不可;仅SET GLOBAL或只关一端均无效。

服务端local_infile=OFF必须写进配置并重启
只执行SET GLOBAL local_infile = OFF是临时的,MySQL重启后恢复旧值。必须编辑配置文件,在[mysqld]段明确写入:local_infile = OFF。常见路径:CentOS 是/etc/my.cnf,Ubuntu/Debian 多为/etc/mysql/mysql.conf.d/mysqld.cnf,Windows 是my.ini。改完必须sudo systemctl restart mysql(或mariadb),reload不生效。
客户端连接时必须显式禁用local_infile
服务端关了,客户端开着照样能发起请求——只是服务端拒收,攻击面仍在。不同客户端禁用方式差异大,漏一个就留后门:
-
mysql命令行:启动时加--local-infile=0,或在~/.my.cnf的[client]段写local_infile = 0 - PyMySQL:连接时传
local_infile=False(注意不是默认值,部分精简包默认裁掉支持) - mysql-connector-python:用
allow_local_infile=False - PHP mysqli:调用
mysqli_options($conn, MYSQLI_OPT_LOCAL_INFILE, false),且必须在mysqli_real_connect()前 - Node.js mysql2:连接选项设
localInfile: false
验证是否真禁用成功,不能只看变量值
SELECT @@local_infile;返回0≠ 安全落地。必须实测:
- 用普通用户登录:
mysql -u user -p(不带--local-infile) - 执行:
LOAD DATA LOCAL INFILE '/tmp/test.csv' INTO TABLE t; - 正确结果应为:
ERROR 1148 (42000): The used command is not allowed with this MySQL version - 若报
ERROR 2068 (HY000): LOAD DATA LOCAL INFILE file request rejected,说明客户端和服务端都拦截了 - 若仍成功——检查是否用了
mysql --local-infile=1连接,或SELECT @@global.local_infile;是否真为0
FILE权限和secure_file_priv也得同步清理
只关local_infile不够,攻击者可能绕过客户端限制,直接让服务端读服务器本地文件:
- 回收所有用户的
FILE权限:REVOKE FILE ON *.* FROM 'user'@'%'; - 设
secure_file_priv = NULL(写在[mysqld]段),彻底锁死LOAD DATA INFILE和SELECT ... INTO OUTFILE - 云环境(如阿里云RDS、AWS Aurora)常不开放配置修改,需确认参数组是否真正应用,不能只信控制台开关
- Docker 启动命令里如果带了
--local-infile,会覆盖配置文件,优先级更高
实际落地时最容易被忽略的是客户端驱动层的默认行为——比如 PyMySQL 某些二进制分发版编译时就没启用local_infile能力,即使你传了True也会静默失败;而另一些版本又默认开,但文档没写清楚。必须逐个环境、逐个驱动实测,不能依赖“配置写了就等于生效”。


















