只关local_infile=off不安全,因其仅控制服务端是否响应load data local infile请求,而实际读取本地文件(如/etc/passwd)的是客户端(如pymysql、mysqli),攻击者可通过sql注入诱使客户端上传并回显敏感文件;必须同步禁用服务端配置、客户端连接参数、回收file权限并设secure_file_priv=null,且逐项验证生效。

为什么只关 local_infile = OFF 不安全?
因为 local_infile 只控制服务端是否响应客户端发来的 LOAD DATA LOCAL INFILE 请求,而实际读取文件的是客户端(比如 Python 的 pymysql、PHP 的 mysqli 或命令行 mysql)。服务端拒绝后,攻击者仍可通过 SQL 注入诱使客户端读取 /etc/passwd 或 ~/.my.cnf 并回显——这不是服务端在读,是客户端被“指挥着读”。
-
SELECT @@local_infile;返回0≠ 安全落地,只是服务端配置生效 - 旧版
mysqli、硬编码local_infile=True的 Python 代码、Docker 镜像默认开启,都可能绕过服务端限制 - 云 RDS(如阿里云、AWS)参数组修改后常需手动“应用”,重启也不一定生效
服务端必须改配置并验证,不能只用 SET GLOBAL
SET GLOBAL local_infile = OFF 是临时设置,MySQL 重启即丢。真正生效必须写进配置文件,并确认无其他段覆盖。
- 编辑
/etc/my.cnf或/etc/mysql/mysql.conf.d/mysqld.cnf,在[mysqld]段添加:local_infile = OFF - 检查是否有
[server]或[mysqld_safe]段又写了local_infile = ON,优先级可能更高 - 执行
sudo systemctl restart mysql(或mariadb) - 连上后立刻运行:
SELECT @@local_infile;—— 必须返回整数0,不是字符串'OFF' - 顺手查:
SELECT @@secure_file_priv;,若为NULL,说明服务端侧的非-LOCAL 版本也已锁死
客户端哪些地方容易漏关 local_infile?
Web 应用最常漏掉连接初始化代码,尤其是老项目或 ORM 封装层。不同客户端禁用方式差异大,漏掉任意一个就等于留后门。
- 命令行:
mysql --local-infile=0 -u user -p,或在~/.my.cnf的[client]段加local_infile = 0 - Python +
pymysql:pymysql.connect(..., local_infile=False)(注意:部分二进制包默认裁剪支持,False不是默认值) - Python +
mysql-connector-python:mysql.connector.connect(..., allow_local_infile=False) - PHP
mysqli:必须在mysqli_real_connect()前调用mysqli_options($conn, MYSQLI_OPT_LOCAL_INFILE, false) - Node.js
mysql2:new Pool({ ..., localInfile: false })
云环境和容器里最容易忽略验证
上线前必须手动连上去跑 SELECT @@local_infile;,不能只信控制台开关或文档描述。Docker 启动命令里如果带了 --local-infile,会直接覆盖配置文件;RDS 参数组修改后不提示是否成功,也未必实时生效。
更隐蔽的风险在于:Go-MySQL-Driver 等库支持白名单机制(如 mysql.RegisterLocalFile()),但多数业务没启用,而是直接依赖全局开关——这意味着只要任一客户端组件漏配,整条链路就失效。安全落地的关键不是“有没有关”,而是“每一处都验证过关了没”。











