必须服务端和客户端同时禁用,只关一端等于没关,因为load data local infile由客户端主动读取本地文件并发送给服务端,服务端local_infile仅控制是否响应请求,而客户端(如mysql命令行、pymysql)默认可能仍协商该能力,若未显式禁用,sql注入即可诱使读取/etc/passwd等敏感文件。

必须服务端和客户端同时禁用,只关一端等于没关。
为什么只改 my.cnf 里的 local_infile = OFF 不够
MySQL 的 LOAD DATA LOCAL INFILE 是客户端主动读本地文件、再发给服务端的流程。服务端变量 local_infile 只控制“收到请求后是否响应”,而客户端(比如 mysql 命令行、pymysql、mysql-connector-python)默认可能仍会尝试协商该能力——只要它没被显式禁止,攻击者就能通过 SQL 注入触发客户端读取 /etc/passwd 或 ~/.my.cnf 并外泄。
- 服务端
local_infile = OFF→ 收到请求直接报错ERROR 1148 (42000) - 服务端
ON但客户端禁用 → 请求根本不会发出,连握手阶段都不带 LOCAL 标志 - 服务端
OFF+ 客户端ON→ 最危险:客户端准备好了,服务端却拒绝,但此时已暴露了客户端环境可读路径
服务端禁用:配置 + 验证两步缺一不可
仅修改配置文件不重启,或重启后没验证,等于白设。
- 在
my.cnf的[mysqld]段写:local_infile = OFF - Linux 下常见路径是
/etc/my.cnf或/etc/mysql/my.cnf;Docker 容器需确认挂载路径是否覆盖 - 重启服务:
sudo systemctl restart mysql(或mariadb) - 连上后立即执行:
SELECT @@local_infile;—— 必须返回0,不是OFF字符串 - 顺手查下
SELECT @@secure_file_priv;,若为NULL,说明服务端连非 LOCAL 的LOAD DATA INFILE也被锁死,但这是另一层防护,不影响当前目标
客户端禁用:不同工具写法完全不同,漏一个就破防
很多团队只关了服务端,却忘了 Web 应用用的 pymysql 或 mysql2 驱动默认仍允许启用——它们不继承服务端配置,必须代码里显式关。
- MySQL CLI:启动时加
--local-infile=0,mysql -u root -p --local-infile=0;别信交互式里SET GLOBAL local_infile = 0,那改的是服务端变量 - Python + PyMySQL:
pymysql.connect(..., local_infile=False),注意是False(不是字符串) - Python + mysql-connector-python:
allow_local_infile=False(8.0.23+ 默认就是False,但旧版要显式传) - PHP mysqli:
mysqli_options($conn, MYSQLI_OPT_LOCAL_INFILE, false),必须在mysqli_real_connect()前调用 - Docker/K8s 场景:镜像里预装的
mysql-client包可能自带默认开启行为,得用 wrapper 脚本封装命令,强制加--local-infile=0
绕过检查的典型场景和堵点
攻防不是静态的。有些看似关严了,实则留了口子。
-
mysql --defaults-file=/tmp/evil.cnf:攻击者伪造配置文件重开local_infile→ 生产环境禁止非白名单用户执行mysql命令,或统一用 shell wrapper 过滤参数 - 云数据库(如阿里云 RDS、AWS RDS):参数组里
local_infile可能灰显不可改,但客户端驱动若开着,仍可能触发协商 → 必须在应用层代码里关死驱动开关 - MySQL 8.0.22+:即使服务端
ON,客户端库握手时默认不再声明支持 LOCAL → 看似安全,但若应用用了旧版 connector 或手动启用了,风险仍在 - CI/CD 流水线或运维脚本里硬编码了
--local-infile=1:这类临时用途最容易被遗忘,建议统一提取为环境变量控制,上线前扫描所有.sh和.py文件中的local_infile关键字
真正容易被忽略的是托管环境里的“隐性客户端”:K8s initContainer 里跑的 mysql-client、Docker Compose 中 links 连接时的默认行为、甚至监控 agent(如 Prometheus mysqld_exporter)的连接参数——它们都可能是未被审计的 local_infile 出口。











