MySQL默认禁用LOAD DATA LOCAL INFILE,因其允许服务端向客户端发起本地文件读取请求,存在SQL注入导致敏感文件泄露的风险;需同时禁用客户端--local-infile=0和服务端local_infile=OFF。

为什么 MySQL 默认禁用 LOAD DATA LOCAL INFILE
因为这个语句会让 MySQL 服务端向客户端发起文件读取请求,实际读的是客户端本地磁盘上的文件。攻击者一旦能控制 SQL 执行(比如 SQL 注入),就可能通过构造恶意查询,诱使 MySQL 客户端(如 PHP 的 mysqli、Python 的 pymysql)把服务器敏感文件(如 /etc/passwd、~/.my.cnf)传回服务端或直接泄露内容。这不是服务端读自己磁盘,而是“反向读客户端”,风险隐蔽且后果严重。
--local-infile=0 到底关的是哪一端
这个参数只控制 MySQL 客户端是否允许发起 LOAD DATA LOCAL INFILE 请求,和服务端无关。即使服务端配置了 local_infile=ON,只要客户端启动时加了 --local-infile=0(或连接时显式禁用),该语句就会报错:ERROR 1148 (42000): The used command is not allowed with this MySQL version。常见场景:
- MySQL 命令行客户端默认启用
local_infile,所以远程连接时若服务端开了,就危险 - PHP
mysqli扩展默认关闭此功能,但可通过mysqli_options($conn, MYSQLI_OPT_LOCAL_INFILE, true)打开 - Python
pymysql默认禁用,需显式传local_infile=True参数才启用
服务端 local_infile 配置的真假影响
服务端的 local_infile 系统变量(可通过 SHOW VARIABLES LIKE 'local_infile' 查看)只是个“许可开关”,它不阻止客户端尝试发送请求,只决定服务端是否响应。也就是说:
- 服务端
local_infile=OFF:收到LOAD DATA LOCAL INFILE请求时直接拒绝,返回错误 - 服务端
local_infile=ON:但客户端禁用了local_infile,请求根本发不出,不会走到服务端校验这步 - 真正起作用的是“客户端允许 + 服务端允许”的交集;任一端关闭,语句就不可用
注意:MySQL 8.0+ 默认服务端 local_infile=OFF,且部分云数据库(如阿里云 RDS)直接移除了该选项,无法开启。
生产环境该关哪几处
不能只靠服务端一刀切。必须分层拦截:
- 客户端连接库初始化时,明确禁用:
mysqli_options(..., MYSQLI_OPT_LOCAL_INFILE, false)(PHP);local_infile=False(PyMySQL / MySQLdb) - MySQL 命令行脚本统一加
--local-infile=0参数,或在~/.my.cnf的[client]段写local_infile=0 - 服务端配置文件中设
local_infile=OFF,并确认未被运行时动态改回(SET GLOBAL local_infile=ON需 SUPER 权限,但仍有风险) - 应用层禁止拼接含
LOAD DATA LOCAL INFILE的 SQL,尤其避免用户输入参与路径构造
最常被忽略的是:开发时用命令行测试开了 local_infile,上线后忘记关客户端配置,或者 ORM 底层驱动悄悄启用了它——这类隐式启用比明文写 SQL 更难审计。










