mysql 5.7+ 默认禁用 load data infile,但需同时检查 secure_file_priv(应设为受限目录)和 local_infile(必须为 off);二者任一配置不当均可能导致本地文件读取风险,且须配合撤销 file 权限。
mysql 5.7+ 默认已禁用 load data infile,但需确认实际状态
很多线上 mysql 实例其实没开这个功能,但运维或开发误配后可能意外启用——它不是“默认开着等你关”,而是“默认关着,但一配就开”。关键看两个地方:secure_file_priv 和 local_infile 系统变量。
执行这条命令就能立刻知道现状:
SELECT @@secure_file_priv, @@local_infile;
如果返回 NULL 或空字符串('')表示 secure_file_priv 未设路径,这是危险信号;如果 @@local_infile 是 ON,哪怕 secure_file_priv 有值,攻击者仍可能通过客户端侧绕过限制读取本地文件(比如用 mysql --local-infile=1 连接)。
-
secure_file_priv控制服务端允许读取的目录,设为/var/lib/mysql-files/是常见做法,设为''或NULL相当于不限制 -
local_infile是客户端开关,MySQL 5.6+ 默认OFF,但某些客户端(如旧版 PHP mysqli、某些 Python 驱动)会强制开启它 - 两者必须同时为安全值:前者非空且路径受限,后者为
OFF
在 my.cnf 中彻底禁用 LOAD DATA INFILE 的写法
不能只改一个参数。要双保险:服务端禁止读任意本地路径 + 客户端禁止发起本地加载请求。
编辑 /etc/my.cnf 或 /etc/mysql/mysql.conf.d/mysqld.cnf,在 [mysqld] 段下加:
secure_file_priv = /var/lib/mysql-files/ local_infile = OFF
注意:secure_file_priv 必须设成一个真实存在的、权限收紧的目录(MySQL 启动用户可读),不能留空也不能设成 /;local_infile = OFF 是硬性关闭客户端支持,比应用层禁用更可靠。
- 改完必须重启 MySQL:
sudo systemctl restart mysql(或mariadb) - 重启后务必再执行
SELECT @@secure_file_priv, @@local_infile;验证是否生效 - 如果用 Docker,需在
my.cnf挂载进容器,并确保配置被mysqld实际加载(可通过mysqld --verbose --help | grep "Default options"查路径)
PHP/Python 应用里还可能偷偷启用 local_infile
即使 MySQL 服务端关了,有些客户端库会在连接时主动请求开启 local_infile,导致报错或绕过风险。这不是漏洞本身,但会让防御失效。
例如 PHP 的 mysqli 扩展,如果初始化连接时用了 MYSQLI_CLIENT_LOCAL_FILES 标志,就会向服务端发请求启用该功能——而服务端若没关死 local_infile,就可能响应成功。
- PHP 中避免这样写:
new mysqli($host, $user, $pass, $db, $port, $socket, MYSQLI_CLIENT_LOCAL_FILES) - Python 的
pymysql默认禁用,但显式设local_infile=True就会触发;mysql-connector-python同理,连上后执行SET GLOBAL local_infile = ON是无效的,但连接参数里带local_infile=True会失败并报错ERROR 1148 (42000): The used command is not allowed with this MySQL version - 只要服务端
local_infile = OFF,客户端无论怎么请求都会被拒绝,但错误信息可能暴露配置细节,所以服务端关死仍是底线
别忽略 MySQL 用户权限和 FILE 权限
LOAD DATA INFILE 不仅依赖全局开关,还受用户权限约束。即使所有配置都关了,如果某个账号有 FILE 权限,且 secure_file_priv 允许读某目录,它仍能从服务端路径加载文件(比如 LOAD DATA INFILE '/var/lib/mysql-files/data.csv')。
所以清理权限也很关键:
REVOKE FILE ON *.* FROM 'app_user'@'%';
-
FILE权限是全局权限,不能按库或表收回,只能整粒度撤销 - 生产环境绝大多数业务账号完全不需要
FILE权限,除非明确要做 ETL 导入 - 检查方式:
SELECT user, host, File_priv FROM mysql.user;
真正麻烦的是那些历史遗留账号,或者用 root 做应用连接的场景——这时候光关配置没用,权限不收,攻击者拿到凭据后照样能读。











