从账号权限最小化到SSL加密,构建生产环境基础防护层
适用于 MySQL 5.7 / 8.0 / 8.4
📋 目录
- 账号权限最小化原则
- 禁用或删除匿名账户与 test 库
- 修改默认端口与绑定监听地址
- 强化密码策略与账号锁定
- 启用 SSL/TLS 加密传输
- 开启审计日志
- 限制 LOAD DATA INFILE 与 FILE 权限
- 关闭不必要的功能与插件
- 定期备份 + 权限完整性校验
- 安全配置文件基线收尾
生产环境的 MySQL 安全加固是一个系统工程,绝不是仅仅设置一个强密码就能了事。本文梳理十项可直接落地的硬核操作,覆盖认证、网络、文件、日志、配置五大安全维度,帮助你构建生产环境的基础防护层。
一、账号权限最小化原则
⚠ 高危 权限管理 最高优先级
生产环境中,任何账号都不应拥有超过其职责所需的权限。常见误区是直接给应用账号赋予 ALL PRIVILEGES,一旦账号泄露后果不堪设想。
操作示例
sql
-- 创建最小权限的应用账号(仅允许特定库的增删改查)
CREATE USER 'app_user'@'192.168.1.%' IDENTIFIED BY 'StrongP@ss2024!';
GRANT SELECT, INSERT, UPDATE, DELETE
ON your_database.*
TO 'app_user'@'192.168.1.%';
FLUSH PRIVILEGES;
-- 查看当前所有账号权限
SELECT user, host, authentication_string FROM mysql.user;
-- 撤销危险权限(SUPER、FILE、PROCESS 等)
REVOKE SUPER ON *.* FROM 'app_user'@'192.168.1.%';
💡 建议为 DBA、只读副本、监控账号分别创建独立用户,账号之间权限完全隔离。Host 字段优先使用精确 IP 或子网段,避免使用 % 通配符。
二、禁用或删除匿名账户与 test 库
⚠ 高危 初始化必做
MySQL 默认安装可能存在空密码的匿名账户和所有用户都可访问的 test 数据库。应在首次部署时立即清理。
操作示例
sql
-- 查找并删除匿名账户
SELECT user, host FROM mysql.user WHERE user = '';
DELETE FROM mysql.user WHERE user = '';
-- 删除 test 数据库及其授权记录
DROP DATABASE IF EXISTS test;
DELETE FROM mysql.db WHERE db = 'test' OR db = 'test\_%';
FLUSH PRIVILEGES;
sql
# 推荐:使用官方安全初始化脚本(MySQL 8.0+)
mysql_secure_installation
⚠️ 执行 mysql_secure_installation 可交互式完成以上清理步骤,同时设置 root 密码、禁止远程 root 登录,是新服务器上线必做项。
三、修改默认端口与绑定监听地址
网络防护 配置项
默认 3306 端口是全网自动化扫描的首要目标。将 MySQL 绑定到内网 IP,并修改为非标准端口,可有效降低被探测和攻击的概率。
my.cnf 配置
sql
[mysqld]
# 修改监听端口(避免使用 3306)
port = 33066
# 仅绑定内网IP,禁止 0.0.0.0 监听
bind-address = 127.0.0.1
# 若需多网卡绑定(MySQL 8.0.13+)
# bind-address = 192.168.1.100,127.0.0.1
# 禁用 MySQL X Protocol(若不使用)
mysqlx = 0
防火墙规则(firewalld)
bash
# 仅允许应用服务器网段访问数据库端口
firewall-cmd --permanent --add-rich-rule='
rule family="ipv4"
source address="192.168.1.0/24"
port protocol="tcp" port="33066"
accept'
firewall-cmd --reload
四、强化密码策略与账号锁定
⚠ 高危 认证安全
MySQL 8.0 引入了 validate_password 组件和失败登录追踪功能,可有效对抗暴力破解。建议同时配置密码过期策略。
安装密码验证组件并配置策略
sql
-- 安装密码验证组件(MySQL 8.0+)
INSTALL COMPONENT 'file://component_validate_password';
-- 配置密码强度策略
SET GLOBAL validate_password.policy = STRONG;
SET GLOBAL validate_password.length = 12;
SET GLOBAL validate_password.mixed_case_count = 1;
SET GLOBAL validate_password.special_char_count = 1;
SET GLOBAL validate_password.number_count = 1;
-- 失败登录追踪:连续失败3次锁定账号1天
ALTER USER 'app_user'@'%'
FAILED_LOGIN_ATTEMPTS 3
PASSWORD_LOCK_TIME 1;
-- 设置密码90天强制过期
ALTER USER 'app_user'@'%'
PASSWORD EXPIRE INTERVAL 90 DAY;
✅ MySQL 8.0 默认认证插件已从 mysql_native_password 切换为更安全的 caching_sha2_password,无需额外配置,但要确保客户端驱动版本支持该插件。
五、启用 SSL/TLS 加密传输
⚠ 高危 传输安全
MySQL 客户端与服务端之间的连接在未启用 SSL 时以明文传输,密码和业务数据均存在被中间人嗅探的风险。生产环境应强制启用 SSL 连接。
第一步:生成证书
bash
# MySQL 自带工具一键生成 CA + 服务端 + 客户端证书
mysql_ssl_rsa_setup --datadir=/var/lib/mysql
# 验证生成的证书文件
ls /var/lib/mysql/*.pem
# ca.pem ca-key.pem server-cert.pem server-key.pem
# client-cert.pem client-key.pem
第二步:my.cnf 配置
sql
[mysqld]
ssl-ca = /var/lib/mysql/ca.pem
ssl-cert = /var/lib/mysql/server-cert.pem
ssl-key = /var/lib/mysql/server-key.pem
# 强制所有连接使用 TLS 1.2+
tls_version = TLSv1.2,TLSv1.3
[client]
ssl-ca = /var/lib/mysql/ca.pem
ssl-cert = /var/lib/mysql/client-cert.pem
ssl-key = /var/lib/mysql/client-key.pem
第三步:对账号强制 SSL
sql
-- 对特定账号强制 SSL(推荐)
ALTER USER 'app_user'@'%' REQUIRE SSL;
-- 更严格:要求双向证书认证(适合 DBA 账号)
ALTER USER 'dba_user'@'%' REQUIRE X509;
-- 验证 SSL 是否生效
SHOW VARIABLES LIKE '%ssl%';
SHOW STATUS LIKE 'Ssl_cipher';
六、开启审计日志
合规审计 可观测性
安全事件发生后,审计日志是还原攻击路径的唯一可靠手段。MySQL Enterprise Edition 提供原生审计插件;社区版可通过开启 General Log 或安装第三方插件实现。
my.cnf 配置(社区版推荐方案)
bash
[mysqld]
# 慢查询日志(推荐常驻开启)
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2
# Binary Log(复制与时间点恢复的基础)
log_bin = /var/log/mysql/mysql-bin
binlog_format = ROW
expire_logs_days = 7
# 通用查询日志(生产环境慎用,性能影响大,可临时开启排查)
# general_log = 1
# general_log_file = /var/log/mysql/general.log
安装审计插件(Enterprise Edition)
sql
-- MySQL Enterprise Audit Plugin
INSTALL PLUGIN audit_log SONAME 'audit_log.so';
SET GLOBAL audit_log_policy = 'ALL';
SET GLOBAL audit_log_format = 'JSON';
SET GLOBAL audit_log_file = '/var/log/mysql/audit.log';
💡 Binary Log(binlog)是数据安全的核心,既支持主从复制,也支持基于时间点的精确恢复(PITR)。生产环境务必开启,且日志文件应存储在独立磁盘分区。
七、限制 LOAD DATA INFILE 与 FILE 权限
⚠ 高危 文件安全
LOAD DATA INFILE 可读取服务器本地文件,FILE 权限允许将数据导出到服务器文件系统。这两个功能是 SQL 注入攻击的高价值目标,若不使用应完全禁用。
my.cnf 配置
bash
[mysqld]
# 禁止 LOAD DATA INFILE 访问服务端文件
local_infile = 0
# 限制 SELECT INTO OUTFILE 只能写入指定目录
secure_file_priv = /var/lib/mysql-files
# ❌ 以下配置极度危险,绝对禁止!
# secure_file_priv = (空值 = 允许写入任意路径)
检查并撤销 FILE 权限
sql
-- 确认没有普通账号拥有 FILE 权限
SELECT user, host, File_priv
FROM mysql.user
WHERE File_priv = 'Y' AND user != 'root';
-- 撤销 FILE 权限
REVOKE FILE ON *.* FROM 'some_user'@'%';
八、关闭不必要的功能与插件
系统加固 配置项
每个启用的功能和插件都是潜在的攻击面。关闭 symbolic-links、禁用不使用的存储引擎和协议,是攻击面最小化原则的直接体现。
my.cnf 配置
bash
[mysqld]
# 禁止符号链接(防止绕过权限访问文件系统)
symbolic-links = 0
# 禁用 FEDERATED 存储引擎(若不使用)
skip-federated
# 禁止 DNS 反向解析(提升连接性能,防止 DNS 欺骗)
skip_name_resolve = 1
# 禁止 SHOW DATABASES 暴露所有库名给普通用户
skip-show-database
# 限制最大连接数,防止连接耗尽攻击(DoS)
max_connections = 500
max_connect_errors = 10
⚠️ 启用 skip_name_resolve 后,GRANT 语句中的 host 只能填写 IP 地址,不能写域名。需提前将所有已有账号的 host 字段更新为 IP 格式。
九、定期备份 + 权限完整性校验
运维 数据保护
备份本身不足够,未经验证的备份等于没有备份。同时应定期审查账号权限分布,发现异常账号和权限漂移。
自动备份脚本
sql
#!/bin/bash
# 建议配合 crontab 每日凌晨执行
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR=/backup/mysql
# 使用 mysqldump 全量备份
mysqldump \
--single-transaction \
--flush-logs \
--master-data=2 \
--all-databases \
-u backup_user -p'BackupP@ss!' \
| gzip > $BACKUP_DIR/full_$DATE.sql.gz
# 验证备份文件大小(小于 1KB 视为异常)
FILESIZE=$(stat -c%s "$BACKUP_DIR/full_$DATE.sql.gz")
[ "$FILESIZE" -lt 1024 ] && echo "[ERROR] 备份文件异常!请检查!"
# 清理7天前的旧备份
find $BACKUP_DIR -name "*.sql.gz" -mtime +7 -delete
权限审计 SQL
sql
-- 定期执行:找出所有拥有全局高危权限的账号
SELECT user, host,
Super_priv, Grant_priv, File_priv,
Shutdown_priv, Process_priv
FROM mysql.user
WHERE Super_priv = 'Y'
OR Grant_priv = 'Y'
OR File_priv = 'Y';
十、安全配置文件基线收尾
基线配置 收尾
将前九项加固操作整合为统一的配置基线,便于版本控制与合规审计。以下是可直接用于生产的 my.cnf 安全基线模板。
生产安全基线 my.cnf
bash
[mysqld]
# ===== 网络安全 =====
bind-address = 127.0.0.1
port = 33066
skip_name_resolve = 1
mysqlx = 0
max_connections = 500
max_connect_errors = 10
# ===== 认证与加密 =====
ssl-ca = /var/lib/mysql/ca.pem
ssl-cert = /var/lib/mysql/server-cert.pem
ssl-key = /var/lib/mysql/server-key.pem
tls_version = TLSv1.2,TLSv1.3
# ===== 文件系统隔离 =====
local_infile = 0
secure_file_priv = /var/lib/mysql-files
symbolic-links = 0
# ===== 功能最小化 =====
skip-federated
skip-show-database
# ===== 日志 =====
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2
log_bin = /var/log/mysql/mysql-bin
binlog_format = ROW
expire_logs_days = 7
配置生效验证
bash
# 重启 MySQL 服务
systemctl restart mysqld
# 验证关键参数是否生效
mysqladmin -u root -p variables | grep -E \
'ssl|local_infile|secure_file|skip_name|max_conn|port'
# 检查数据库完整性
mysqlcheck --all-databases -u root -p
✅ 配置完成后,建议使用 MySQLTuner 或 Percona Security Check 对实例进行全面安全扫描,输出安全评分报告,留存作为合规依据。
🛡️ 十大加固操作总结
| # | 操作 | 安全维度 | 优先级 |
|---|---|---|---|
| 1 | 账号权限最小化 | 认证安全 | 🔴 最高 |
| 2 | 清理匿名账户 / test 库 | 认证安全 | 🔴 最高 |
| 3 | 修改端口 + 绑定内网 IP | 网络防护 | 🟠 高 |
| 4 | 密码策略 + 登录锁定 | 认证安全 | 🔴 最高 |
| 5 | SSL/TLS 加密传输 | 传输安全 | 🔴 最高 |
| 6 | 审计日志 + Binlog | 合规审计 | 🟠 高 |
| 7 | 禁用 FILE / LOAD DATA | 文件安全 | 🔴 最高 |
| 8 | 关闭不必要功能插件 | 系统加固 | 🟡 中 |
| 9 | 定期备份 + 权限校验 | 数据保护 | 🟠 高 |
| 10 | 安全基线配置统一管理 | 配置管理 | 🟡 中 |
--- 如有问题欢迎评论区交流,觉得有用的话点个赞吧 👍 ---