必须服务端和客户端双侧禁用local_infile,且收回file权限、设secure_file_priv=null,缺一不可;仅关服务端配置无法阻止攻击者通过sql注入诱导客户端读取敏感文件。

为什么只关 local_infile = OFF 不够?
因为 LOAD DATA LOCAL INFILE 的实际文件读取行为发生在客户端——MySQL 服务端只是接收已读取的数据。即使服务端设了 local_infile = OFF,攻击者仍可通过 SQL 注入诱导客户端(如 Python 脚本、mysql CLI)主动读取 /etc/passwd 或 ~/.my.cnf 并回显。所以必须同时掐断服务端响应能力 + 客户端发起能力 + 权限入口。
必须同时禁用的四个关键点
缺一不可,漏掉任一环节都等于没防:
- 服务端配置:
local_infile = OFF写进[mysqld]段,然后sudo systemctl restart mysql;验证用SELECT @@global.local_infile;必须返回0 - 客户端默认关闭:
local-infile = 0写进[mysql]段(不是[mysqld]),否则 mysql 命令行默认仍协商 LOCAL 能力 - 回收
FILE权限:REVOKE FILE ON *.* FROM 'username'@'host';,包括 root 用户(它不参与日常业务,不该有该权限) - 锁定服务端文件路径:
secure_file_priv = NULL写进[mysqld]段并重启;SELECT @@secure_file_priv;必须返回NULL,而非空字符串''(那是最危险状态)
常见踩坑场景
这些地方最容易出问题,且不易察觉:
- Docker 镜像或云 RDS 修改参数后未“应用配置”,仅重启 mysqld 无效;必须确认配置已真正加载(查
SHOW VARIABLES LIKE 'local_infile'和secure_file_priv) - Python 代码里硬编码
local_infile=True(如 PyMySQL / MySQLdb),覆盖了客户端配置;需全局搜local_infile并删掉或设为False - 误以为
SET GLOBAL local_infile = 0是永久生效——这只是会话级临时设置,重启即丢 -
secure_file_priv设成目录(如/var/lib/mysql-files/)后没收紧该目录权限:必须确保只有mysql用户可写、其他用户不可读
验证是否真禁死
别信配置文件,要实测:
- 用普通用户连接:
mysql -u appuser -p(不加--local-infile) - 执行:
LOAD DATA LOCAL INFILE '/etc/passwd' INTO TABLE t;,应报错ERROR 1148 (42000)或ERROR 2068 (HY000) - 再试服务端侧:
LOAD DATA INFILE '/etc/passwd' INTO TABLE t;,若secure_file_priv = NULL,应直接报错ERROR 1290 (HY000) - 检查残留权限:
SELECT User,Host,File_priv FROM mysql.user WHERE File_priv='Y';,结果应为空
只要其中任意一条能成功,说明防护链存在断裂点,得回头逐项排查。











