禁用符号链接必须配置skip_symbolic_links=yes且同步设置local_infile=0、回收file权限;have_symlink仅为只读状态标识,非可配置项,不能用于安全控制。

不能靠 have_symlink=NO 配置来禁用符号链接——它根本不是可写配置项,只是只读状态标识。真正起作用的只有 skip_symbolic_links=yes,且必须配合 local_infile=0 和权限管控,否则攻击者仍可通过 LOAD DATA INFILE + 符号链接组合绕过限制。
为什么 have_symlink 不是开关,而只是“体检报告”
have_symlink 是 MySQL 启动时探测操作系统是否支持符号链接后自动设置的只读变量。它返回 YES 仅表示「系统能力就绪」,不代表 MySQL 当前允许你用;返回 NO 也不代表你关对了,可能是系统压根不支持(比如某些容器环境)。想控制行为,必须改配置项,而不是查这个值。
常见错误现象:
- 在配置里写了
have_symlink=NO,重启后无效,SHOW VARIABLES LIKE 'have_symlink'依然显示YES - 误以为
have_symlink=NO就安全了,结果仍能用CREATE TABLE ... DATA DIRECTORY='/tmp'成功建表
skip_symbolic_links=yes 必须写在 [mysqld] 段,且 5.6+ 版本不认 symbolic-links=0
MySQL 5.6 起,symbolic-links 参数已被标记为废弃;8.0.33+ 版本会直接忽略它并静默启用符号链接。唯一可靠写法是:
[mysqld] skip_symbolic_links=yes local_infile=0
注意点:
- 必须写在
[mysqld]段下,写在[client]或全局段无效 - 不要和
symbolic-links=0共存,避免配置冲突或被后者覆盖 -
local_infile=0必须同步关闭——否则即使禁了符号链接,攻击者仍可用LOAD DATA LOCAL INFILE '/proc/self/environ'读取敏感文件
验证是否真生效:别只看 have_symlink,要看报错和行为
配置重启后,仅查 @@skip_symbolic_links 返回 1 还不够。必须实测触发路径解析:
- 执行
CREATE TABLE t1 (id INT) DATA DIRECTORY='/tmp/testdir';—— 应报错ERROR 1030 (HY000): Got error 168 from storage engine或类似拒绝提示 - 执行
SELECT @@skip_symbolic_links;确认返回1(注意不是have_symlink) - 检查
SHOW VARIABLES LIKE 'local_infile';确保返回OFF
如果 DATA DIRECTORY 仍成功创建,说明配置未加载(比如改错了配置文件路径、没重启服务、或被其他 my.cnf 覆盖)。
容易被忽略的联动风险:权限 + 用户策略才是最后一道墙
即使 skip_symbolic_links=yes 和 local_infile=0 都开了,只要账号有 FILE 权限,仍可能通过其他方式绕过。所以必须同步做:
- 回收所有非必要账号的
FILE权限:REVOKE FILE ON *.* FROM 'appuser'@'%'; - 禁止高危账号远程登录:
DROP USER IF EXISTS 'root'@'%'; - 确保 MySQL 以普通用户(如
mysql)而非root运行,否则符号链接一旦绕过,等于拿下宿主机 root 权限
最常被漏掉的是:开发账号仍保留 FILE 权限用于本地调试,但上线后没清理——这会让前面所有配置形同虚设。











