ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

mysql_secure_installation详解:MySQL安全初始化加固与实战指南

mysql_secure_installation详解:MySQL安全初始化加固与实战指南 刚帮一个朋友处理完线上 MySQL 被扫库的事故又想起了这个几乎每个 MySQL 新手都会遇到、但很少真正重视的命令mysql_secure_installation。很多人装完 MySQL 第一件事就是急着建库、导数据、连业务安全脚本要么跳过要么“一路回车”等出事了才回头看文档。这篇我就用实际执行的经验把这个脚本从头到尾拆一遍包括每一步会问什么、为什么要这么选、哪些环境不能无脑跑、以及跑完之后还需要哪些补充动作。mysql_secure_installation是 MySQL 官方自带的安全初始化脚本用来在刚装完 MySQL 之后把那些开箱即用的“不安全默认设置”一次性收掉。它的核心价值就一句话把数据库从“能跑”变成“能放心跑”。无论你是用 rpm、apt 装的 MySQL还是用二进制包解压部署的只要 MySQL 版本带了这个脚本5.7 到 8.x 都有都应该在正式使用前执行一遍。下面我按实际执行时会遇到的每一项交互逐条说明怎么选、为什么。1. 新装 MySQL 的第一道坎默认状态有多“裸”先说个最典型的场景。你刚在服务器上装完 MySQLsystemctl start mysqld一看服务正常mysql -uroot -p也能进去好像一切搞定。但这时候如果你的服务器有公网 IP或者在内网里安全域划分不够细MySQL 的默认状态就是门户大开。默认安装的 root 账号通常允许从任意主机连接取决于安装方式有些甚至还带着空密码默认还附带一个任何人都能访问的 test 库匿名用户在某些发行版里也是存在的。我见过不少新手直接把阿里云或腾讯云的 MySQL 端口 3306 暴露在公网然后用 root 弱密码甚至空密码跑业务。这类实例被自动扫描工具盯上只是时间问题轻则数据被删勒索重则直接被加密、被植入后门。mysql_secure_installation就是为这个场景准备的它本质上是一个交互式加固向导逐项帮你处理掉高风险配置。那它具体做了什么我梳理了一下主要覆盖五个方面给 root 设置密码或重新校验已有 root 密码强度。删除默认的匿名用户。限制 root 只能从 localhost 登录禁止远程 root。删除默认的 test 数据库及对它的访问权限。刷新权限表让上述变更立即生效。这五条听起来简单但每一条背后都有真实的安全事故做注脚。匿名用户如果不清掉同网段的任何人不需要密码就能以匿名身份连上来root 可以远程登录的话暴力破解工具会优先拿 root 当目标test 库本身虽然无害但它默认对所有人开放等于多了一个可探测的入口。所以这脚本不是走过场是真能挡掉相当一部分低级攻击。执行方式也很简单在 shell 里敲mysql_secure_installation如果你用的是 MariaDB命令也是一样的但交互项措辞略有差异。接下来它会用一问一答的方式带着你走完全部流程下面我按实际执行顺序把每一项拆开讲。2. 交互项逐条拆解每一步背后都有讲究脚本在不同版本里问的问题顺序和措辞会有一点点差别但核心逻辑稳定。我就按 MySQL 8.0 系列最常见的交互顺序来说。2.1 密码校验策略VALIDATE PASSWORD COMPONENT这一步问的是Press y|Y for Yes, any other key for No:问你是否要安装密码校验插件。安装后它会强制 root 口令满足一定的复杂度要求。MySQL 8.0 里这个组件叫validate_password策略分三档LOW只检查长度默认至少 8 位。MEDIUM长度 数字 大小写 特殊字符。STRONG在 MEDIUM 基础上还要检查包含至少一个字典单词或自定义单词列表。我建议直接选是并且策略选 MEDIUM 或 STRONG。尤其是生产环境root 口令强度就是数据库的第一道门锁。开发环境如果你嫌烦至少要选 LOW长度下限别低于 8 位。这里有个实际经验如果你是在已有实例上执行这个流程当前 root 密码本身不符合新策略的话脚本会要求你先改掉旧密码再继续。这种情况下先准备一个满足策略的新密码免得在中途被卡住。2.2 设置 root 密码接着它会要求输入 root 新密码并确认。如果你已经有密码这一步相当于重置。注意这里它校验的不只是“你记不记得住”而是密码复杂度。实测中很多人栽在这个环节——密码里带、#这类字符时在 shell 脚本交互式输入没问题但如果之后要在命令行里拼mysql -p密码转义问题会害你折腾半天。我建议密码里尽量避免单引号和空格其他特殊字符可以保留。这个环节没有捷径但在自动化部署时你可以不手动交互而是用以下方式设置mysqladmin -u root password 新密码或者在进入 MySQL 后用 ALTER USER 来改ALTER USER rootlocalhost IDENTIFIED BY 新密码;2.3 删除匿名用户脚本接着问Remove anonymous users?是否删除匿名用户。这个必须选 Y。匿名用户意味着任何能连到 3306 端口的人都可以在不知道账号密码的情况下先建立连接然后再尝试提权或探测库表。虽然 MySQL 的匿名用户通常权限很低但它属于一个不必要的攻击面。有的发行版比如 Debian 系的 MySQL 包默认就不创建匿名用户所以这步可能不会出现。如果出现说明你的初始安装包含了匿名账户选 Y 删除就是了。2.4 禁止 root 远程登录Disallow root login remotely?这一项是争议比较多的。它做的事情是移除root%这类允许远程连接的账号只保留rootlocalhost。生产环境我强烈建议选 Y。root 只用于本机管理业务连接全部走独立账号。这样即使应用侧密码泄露也只是业务库的权限不是整个实例的控制权。开发环境如果确实有远程管理需求也应该创建专用管理账号而不是放行 root 远程。如果因为历史原因需要远程 root比如数据库在 Docker 里宿主机要连进去管理正确的做法不是在这步选 N而是通过配置项和账号白名单限制来源 IP并且开启 SSL 连接。这个后面单独说。2.5 删除 test 库和测试相关的访问权限Remove test database and access to it?建议选 Y。默认的 test 库存在两个问题一是它对所有用户开放包括匿名用户二是它常用于攻击者存放临时表。删掉它不会影响任何正常业务需要测试环境自己单独建库即可。我见过有些老项目把临时数据直接丢在 test 库里的跑这个脚本之前最好检查一下SHOW DATABASES LIKE test%;是否有遗留数据有就先备份再删。2.6 刷新权限表最后一步问Reload privilege tables now?选 Y。它会执行FLUSH PRIVILEGES让前面的权限变更立即生效。这个操作在 MySQL 里不算重但对一致性很重要——不刷新的话某些权限修改在部分场景下要到下一次连接或重启才生效排查问题时容易产生“明明改了怎么没用”的错觉。刷完之后脚本会显示一条成功提示并退出。到这里一个“干净”的初始状态就建立好了。3. 执行过程中的差异与意外情况上面讲的是理想流程。实际执行中你会发现不同版本、不同安装方式之间差异不小我把自己遇到过的几种情况列出来。3.1 找不到命令或提示命令不存在用二进制包解压部署 MySQL 时mysql_secure_installation通常位于 MySQL 安装目录的bin下且不会自动加入 PATH。你需要全路径执行/usr/local/mysql/bin/mysql_secure_installation或者先export PATH/usr/local/mysql/bin:$PATH再执行。用 rpm 或 apt 安装的一般已经加入 PATH直接执行即可。3.2 Socket 连接失败Can’t connect to local MySQL server through socket脚本默认通过 Unix socket 连接本机的 MySQL。如果你在容器里跑或者 MySQL 配置了 socket 路径可能出现连接失败。解决方式有几种确认 MySQL 服务已经在运行systemctl status mysqld或service mysql status。在脚本执行时指定 socket 路径。MySQL 8.0 的mysql_secure_installation支持通过环境变量或配置文件方式指定更简单的办法是先在/etc/my.cnf里把 socket 路径配置好让脚本读到。个别情况下脚本还会读取~/.my.cnf里的客户端配置如果你之前创建过这个文件里面指向了错误的 socket 路径也会造成连不上。3.3 root 密码策略设置只有 LOW 和 MEDIUM没有 STRONGMySQL 8.0 里如果你没安装完整的 validate_password 组件脚本可能只提供 LOW 和 MEDIUM。实际上完整的组件安装后 STRONG 档位才可用。安装方式是INSTALL COMPONENT file://component_validate_password;然后SHOW VARIABLES LIKE validate_password.policy;查看当前策略。如果想调到 STRONG需要同时设置validate_password.dictionary_file字典文件不然设置会报错。3.4 已有业务数据时执行脚本要非常小心mysql_secure_installation不是只能在新装环境跑已有实例也可以跑但必须评估影响。最典型的情况是你有一个老项目连接数据库用的就是 root 账号且项目配置里写的是远程连接地址。这时如果脚本把 root 的远程登录禁用掉业务就断了。我的建议是对已有实例执行前先做三件事打开general_log或查询performance_schema里的连接记录确认当前有哪些账号在连、从哪里连。把业务账号建好并授权确保不依赖 root。在低峰期操作并且先在测试环境完整演练一遍。3.5 自动化执行echo 管道与 expect生产环境中有大量实例需要统一加固时手动一个个跑显然不现实。这里提供两种自动化方案但注意密码会暴露在进程参数或脚本文件中须做好权限管理。第一种用echo管道传入回答mysql_secure_installation EOF y 2 新密码 新密码 y n y y EOF顺序对应是否启用密码组件、选择策略级别、输入 root 密码、确认密码、是否删除匿名用户、是否禁用 root 远程n 表示保留、是否删除 test 库、是否刷新权限表。第二种用 expect#!/usr/bin/expect spawn mysql_secure_installation expect VALIDATE PASSWORD send y\r expect policy send 2\r expect password send 新密码\r send 新密码\r expect Remove anonymous users send y\r ...这两种方式我都用过expect更稳但需要安装额外依赖。echo管道在密码含特殊字符时会踩坑建议密码先临时改成简单字母数字组合再执行执行后再改成正式密码。4. 脚本之外N 个容易被忽略的加固动作mysql_secure_installation处理的是基础项但它管不到的地方其实更多。我自己给客户做数据库巡检时发现很多实例虽然跑了安全脚本防护状态仍然存在明显短板。以下几个是我认为最值得补的。4.1 监听地址别让 MySQL 暴露在所有网卡上默认配置下MySQL 可能监听0.0.0.0:3306。安全脚本不会管这件事。正确做法是在/etc/my.cnf里设置[mysqld] bind-address127.0.0.1如果业务需要远程连接绑定内网 IP 或专网 IP不要把 3306 直接暴露到公网。Docker 环境里则通过端口映射控制暴露范围一般只映射到宿主机回环地址再由反向代理转发。4.2 独立业务账号和最小权限root 只保留本机管理用途业务账号按库授权。比如业务只需要读写一个库就只授予SELECT, INSERT, UPDATE, DELETE不要给ALL PRIVILEGES更不能给GRANT OPTION。这样即使数据库账号被注入或泄露攻击面也被限制在一个数据库内。4.3 开启连接加密MySQL 8.0 默认自带 SSL但要确认是否真的生效。用管理员账号执行SHOW VARIABLES LIKE have_ssl; SHOW VARIABLES LIKE ssl_ca;如果有输出说明 SSL 已启用。为了让各客户端默认走加密连接可以在配置里调整相关选项同时创建用户时用REQUIRE SSL限制指定账号必须使用加密连接。这个对于防止链路嗅探、账号密码被截获很有意义。4.4 审计与日志MySQL 8.0 有自己的审计插件MySQL Enterprise Audit社区版则可通过general_log做临时排查或借助第三方工具做 SQL 审计。实际运维中我至少建议开启以下日志log_error错误日志默认开启用于故障排查。log_bin二进制日志既用于主从复制也用于误操作后的时间点恢复。slow_query_log慢查询日志配合长查询阈值调优日常性能排查必备。安全脚本不会帮你开这些但它们对“事故后恢复”和“入侵后溯源”的作用极大。等真出事了你再想开可能已经晚了。4.5 备份与恢复演练这一点和安全脚本没有直接关系但不能不提。任何安全加固都无法保证 100% 防住攻击而备份是最后一道防线。我见过太多公司备份了但从没恢复过等到需要恢复时发现备份文件已损坏。建议定期做一次完整的mysqldump或物理备份并在测试环境演练恢复流程。5. 最后分享几条实战体会写到这里把几个和这个脚本相关的经验再沉淀一下。第一不要让mysql_secure_installation变成一次性的“仪式”。很多团队装完 MySQL 跑一遍就彻底忘了它的存在但等 MySQL 大版本升级、迁移、或者从开发库转生产库时新环境的安全基线可能又回到了默认状态。我把这个脚本当作环境验收清单的一部分每次部署都要在文档里打勾确认。第二密码策略设得太强也未必是好事。STRONG 策略在 MEDIUM 基础上增加了字典检查人难记、自动化脚本也容易踩坑。我一般对 root 用 STRONG业务账号用 MEDIUM管理账号用 STRONG。密码尽量放在密钥管理服务里不要明文写在配置文件或代码仓库中。第三执行脚本时如果提示当前密码不符合策略先别急着把策略调低。检查是不是只设置了validate_password.length而没处理其他变量。合理做法是完整安装 validate_password 组件后再调策略档位避免后续出现配置不一致的情况。第四Docker 环境下执行这个脚本有个小坑容器里的 MySQL 通常不装 expect 一类的交互工具直接用docker exec -it mysql mysql_secure_installation会因为没有 TTY 而报错。可以先docker exec -it mysql bash进入容器再执行脚本。如果镜像做了精简可能连脚本都没有这时就得手动执行对应的 SQL 语句比如DELETE FROM mysql.user WHERE User; DROP DATABASE IF EXISTS test; DELETE FROM mysql.db WHERE Dbtest OR Dbtest\\_%; ALTER USER rootlocalhost IDENTIFIED BY 新密码; FLUSH PRIVILEGES;这一套 SQL 其实和脚本干的事一模一样。理解了脚本的底层逻辑手动加固也完全不困难。第五也是我最想强调的一点别指望一个脚本解决所有安全问题。它更像是给你清理了房间里的明面垃圾但防火墙、账号权限、加密、备份这些“结构性安全”还得靠日常运维投入。把安全脚本跑完只是一个起点。
返回列表