LOAD_FILE被利用的前提是:用户拥有FILE权限、目标文件为绝对路径且MySQL进程可读、secure_file_priv非NULL且路径在其允许范围内;设为NULL可彻底禁用LOAD_FILE等文件操作。

LOAD_FILE 被利用的前提是什么
LOAD_FILE() 函数能读取服务器本地文件,前提是:
- 当前用户拥有
FILE权限 - 目标文件路径是绝对路径,且 MySQL 进程有读权限
-
secure_file_priv的值不为NULL,且目标路径在允许范围内(或配置为空字符串)
如果攻击者已通过 SQL 注入拿到高权限账号,又恰好 secure_file_priv 设为空字符串或宽松路径,LOAD_FILE('/etc/passwd') 就可能直接返回系统敏感内容。
为什么设成 NULL 是最有效的防御手段
secure_file_priv = NULL 会让所有依赖文件 I/O 的操作直接失败,包括:
-
LOAD DATA INFILE -
SELECT ... INTO OUTFILE -
LOAD_FILE()函数
这不是“限制路径”,而是彻底切断能力。哪怕用户有 FILE 权限,执行 LOAD_FILE('/tmp/x') 也会报错:ERROR 1290 (HY000): The MySQL server is running with the --secure-file-priv option。
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
注意:设为 NULL 后,SHOW VARIABLES LIKE 'secure_file_priv' 返回结果就是 NULL,不是空字符串或路径,别误判。
配置 secure_file_priv = NULL 的实操要点
- 修改 MySQL 配置文件(如
/etc/my.cnf 或 /etc/mysql/mysql.conf.d/mysqld.cnf),在 [mysqld] 段落下写:
secure_file_priv = NULL
- 不要加引号,不要写成
'NULL' 或 ""
- 该变量不可动态修改:
SET GLOBAL secure_file_priv = NULL 会报错 Variable 'secure_file_priv' is a read only variable
- 必须重启 MySQL:用
systemctl restart mysql(不是 reload)
- 重启后验证:
SELECT @@secure_file_priv; 应返回 NULL(不是字符串 "NULL")
绕过 NULL 防御的常见误判点
/etc/my.cnf 或 /etc/mysql/mysql.conf.d/mysqld.cnf),在 [mysqld] 段落下写:secure_file_priv = NULL 'NULL' 或 "" SET GLOBAL secure_file_priv = NULL 会报错 Variable 'secure_file_priv' is a read only variable systemctl restart mysql(不是 reload) SELECT @@secure_file_priv; 应返回 NULL(不是字符串 "NULL")有些场景看似“绕过”,其实是配置没生效或理解偏差:
- Web 应用自己用 PHP/Python 读取文件再插入数据库 → 这和
LOAD_FILE无关,secure_file_priv管不到应用层 - 攻击者用
SELECT LOAD_FILE(0x2f6574632f706173737764)(十六进制路径)→ 依然被NULL拦住,编码不改变函数语义 - 误以为
secure_file_priv = ''和NULL效果类似 → 实际相反:''是完全放开,8.0+ 启动时会警告“Empty value for secure_file_priv is deprecated” - 忘记检查配置是否被多处覆盖:Docker 启动参数、
mysqld --defaults-file、include引入的其他 conf 文件都可能覆盖主配置
真正起作用的只有最终生效的那个 @@secure_file_priv 值,其他全是干扰项。

















