前言
mysql 加固核心目标:限制未授权访问、最小化权限暴露、加密敏感数据、审计操作行为,以下方案覆盖从基础配置到高级防护的全流程,适配 mysql 5.7+ / 8.0+(标注版本差异处需重点注意)。
一、基础环境加固(系统 + 安装层面)
1. 升级到稳定安全版本
旧版本(如 5.6 及以下)存在大量未修复漏洞(如权限绕过、sql 注入),优先升级至:
- mysql 5.7.30+(lts 长期支持版)
- mysql 8.0.20+(推荐,安全性更强,默认认证插件更安全)
升级检查:
select version(); -- 查看当前版本
2. 以非 root 用户运行 mysql
默认 mysql 可能以 root 用户启动,若被入侵可能导致服务器提权,需创建专用低权限用户:
# 1. 创建 mysql 系统用户(若未创建) useradd -r -s /sbin/nologin mysql # 2. 修改数据目录/配置文件权限(linux 示例) chown -r mysql:mysql /var/lib/mysql # 数据目录 chown -r mysql:mysql /etc/my.cnf # 配置文件 chmod 700 /var/lib/mysql # 仅属主可读写 chmod 600 /etc/my.cnf # 仅属主可修改 # 3. 重启 mysql 并验证运行用户 systemctl restart mysqld ps -ef | grep mysqld | grep -v grep # 确认进程属主为 mysql
3. 清理无用组件与文件
- 卸载未使用的存储引擎(如 csv、blackhole,仅保留 innodb);
- 删除安装残留的测试数据库(
test库)和示例表; - 移除无用的脚本(如
mysql_install_db旧脚本,mysql 8.0 已废弃)。
删除 test 库:
drop database if exists test;
二、访问控制加固(核心:限制 “谁能连、从哪连”)
1. 初始化安全配置(必做)
mysql 提供内置工具 mysql_secure_installation,一键完成基础加固(需登录 mysql 后执行):
mysql_secure_installation
按提示完成以下操作:
- 设置 / 修改 root 密码(若未设置);
- 移除匿名用户(
anonymous用户,允许空密码登录); - 禁止 root 用户远程登录(默认仅允许 localhost 访问);
- 删除 test 数据库及匿名用户对所有数据库的访问权限;
- 刷新权限表(
flush privileges)。
2. 清理冗余 / 危险用户
(1)查看所有用户及登录主机
-- mysql 5.7+ select user, host, authentication_string from mysql.user; -- mysql 8.0+(默认认证插件为 caching_sha2_password) select user, host, plugin from mysql.user;
(2)删除无用用户
- 匿名用户(
user=''或host='%'的空用户); - 长期未使用的账号;
- 权限过大的普通用户。
-- 删除匿名用户(示例) drop user if exists ''@'localhost'; drop user if exists ''@'%'; -- 删除指定用户(如 test@'%') drop user if exists 'test'@'%'; flush privileges; -- 刷新权限
3. 限制用户登录主机(最小化访问范围)
避免用户以 host='%'(允许所有主机登录),仅授权信任的 ip / 网段:
-- 示例1:仅允许本地登录(推荐 root 用户) create user if not exists 'root'@'localhost' identified by 'strongp@ss123'; -- 示例2:允许指定 ip 登录(如办公网 192.168.1.0/24 网段) create user if not exists 'appuser'@'192.168.1.%' identified by 'appp@ss456'; -- 错误示例(禁止):允许所有主机登录 create user 'baduser'@'%' identified by 'weakpass'; -- 风险极高
4. 最小权限原则分配权限
(1)拒绝给普通用户高危权限
以下权限仅授予 root 或管理员,禁止给应用用户:
super:修改全局参数、终止线程(可能用于提权);file:读写服务器文件(可能泄露敏感数据或写入恶意文件);shutdown:关闭 mysql 服务;create user:创建 / 删除用户(权限滥用风险);alter/drop:修改 / 删除表(误操作或恶意破坏)。
(2)应用用户权限示例(仅授予必要权限)
-- 给应用用户仅授予指定库的查询/插入/更新权限 grant select, insert, update on appdb.* to 'appuser'@'192.168.1.%'; -- 给只读用户仅授予查询权限 grant select on appdb.* to 'readuser'@'192.168.1.%'; flush privileges;
(3)定期回收未使用权限
-- 查看用户权限 show grants for 'appuser'@'192.168.1.%'; -- 回收权限(如回收 update 权限) revoke update on appdb.* from 'appuser'@'192.168.1.%';
三、密码安全加固(防止暴力破解)
1. 设置强密码策略
(1)mysql 5.7+ 配置(通过validate_password插件)
-- 启用密码验证插件(默认已启用,若未启用则执行) install plugin validate_password soname 'validate_password.so'; -- 查看当前密码策略 show variables like 'validate_password%'; -- 设置强密码规则(修改 my.cnf 永久生效) [mysqld] validate_password_length = 12 # 密码最小长度 12 位 validate_password_policy = strong # 强策略(需包含大小写、数字、特殊字符) validate_password_special_char_count = 1 # 至少 1 个特殊字符 validate_password_mixed_case_count = 1 # 至少 1 个大小写字母
(2)mysql 8.0+ 配置(默认启用validate_password,策略更严格)
-- 8.0 新增参数,禁止密码与用户名/主机名相同 set global validate_password_check_user_name = on; -- 永久生效(my.cnf) [mysqld] validate_password_length = 12 validate_password_policy = strong validate_password_check_user_name = on
2. 定期更换密码 + 密码过期策略
-- 设置用户密码过期时间(90 天,mysql 5.7+ 支持) alter user 'appuser'@'192.168.1.%' password expire interval 90 day; -- 强制用户下次登录修改密码 alter user 'appuser'@'192.168.1.%' password expire force; -- 禁止重复使用最近 5 次密码(mysql 8.0+ 支持) set global password_history = 5;
3. 禁用明文存储密码
- mysql 5.7+ 默认使用
mysql_native_password插件(哈希存储,仍有破解风险); - mysql 8.0+ 默认使用
caching_sha2_password插件(更安全,支持加盐哈希),建议所有用户切换至此插件:
-- 修改用户认证插件(mysql 8.0+) alter user 'appuser'@'192.168.1.%' identified with caching_sha2_password by 'newstrongp@ss789'; -- 全局默认使用 caching_sha2_password(my.cnf) [mysqld] default_authentication_plugin = caching_sha2_password
四、网络安全加固(防止网络层面攻击)
1. 绑定内网 ip,禁止公网监听
默认 mysql 监听 0.0.0.0(所有网卡),易被公网扫描,修改 my.cnf 绑定内网 ip:
[mysqld] bind-address = 192.168.1.100 # 仅监听内网 ip # 若无需远程访问,直接绑定 localhost # bind-address = 127.0.0.1
重启 mysql 后验证:
netstat -tuln | grep 3306 # 确认仅监听指定 ip:3306
2. 防火墙限制 3306 端口访问
仅允许信任的 ip / 网段访问 mysql 端口(3306),禁止公网开放。
(1)linux 防火墙(firewalld)
# 允许 192.168.1.0/24 网段访问 3306 firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.0/24" port protocol="tcp" port="3306" accept' # 禁止其他所有 ip 访问 3306 firewall-cmd --permanent --remove-port=3306/tcp # 重新加载防火墙规则 firewall-cmd --reload # 验证规则 firewall-cmd --list-rich-rules
(2)windows 防火墙
在 “高级设置” 中创建入站规则:仅允许指定 ip 访问 3306 端口,拒绝其他所有。
3. 启用 ssl/tls 加密传输(防止数据窃听)
mysql 传输默认明文,需启用 ssl 加密客户端与服务器的通信(mysql 5.7+ 支持,8.0+ 默认推荐)。
(1)生成 ssl 证书(自签或 ca 签发)
# 生成 ca 证书(有效期 3650 天) openssl genrsa 2048 > ca-key.pem openssl req -new -x509 -nodes -days 3650 -key ca-key.pem > ca.pem # 生成服务器证书 openssl req -newkey rsa:2048 -days 3650 -nodes -keyout server-key.pem > server-req.pem openssl rsa -in server-key.pem -out server-key.pem openssl x509 -req -in server-req.pem -days 3650 -ca ca.pem -cakey ca-key.pem -set_serial 01 > server-cert.pem # 生成客户端证书(供应用连接使用) openssl req -newkey rsa:2048 -days 3650 -nodes -keyout client-key.pem > client-req.pem openssl rsa -in client-key.pem -out client-key.pem openssl x509 -req -in client-req.pem -days 3650 -ca ca.pem -cakey ca-key.pem -set_serial 02 > client-cert.pem # 修改证书权限(仅 mysql 用户可读) chmod 600 *.pem chown mysql:mysql *.pem mv *.pem /etc/mysql/ssl/ # 移动到安全目录
(2)配置 mysql 启用 ssl(my.cnf)
[mysqld] ssl-ca = /etc/mysql/ssl/ca.pem ssl-cert = /etc/mysql/ssl/server-cert.pem ssl-key = /etc/mysql/ssl/server-key.pem # 强制客户端使用 ssl 连接(可选,增强安全性) require_secure_transport = on # mysql 8.0+ 支持;5.7 用 ssl=1
(3)验证 ssl 启用
-- 服务器端验证 show variables like '%ssl%'; # 若 have_ssl 为 yes 则启用成功 -- 客户端连接验证(需携带证书) mysql -u appuser -p -h 192.168.1.100 --ssl-ca=/etc/mysql/ssl/ca.pem --ssl-cert=/etc/mysql/ssl/client-cert.pem --ssl-key=/etc/mysql/ssl/client-key.pem -- 连接后验证 ssl 状态 status; # 查看 ssl 行是否为 cipher in use: xxx
4. 禁用 load data local infile(防止文件泄露)
load data local infile 允许客户端读取服务器本地文件,可能被利用泄露敏感数据(如 /etc/passwd),禁用:
[mysqld] local-infile = 0 # 服务器端禁用 [mysql] local-infile = 0 # 客户端禁用
五、数据安全加固(保护数据不泄露、不丢失)
1. 启用 innodb 透明加密(tde,mysql 8.0.16+ 支持)
对数据文件加密,防止磁盘被盗导致数据泄露:
[mysqld] innodb_encrypt_tables = on # 全局启用表加密 innodb_encrypt_log = on # 重做日志加密 innodb_encryption_threads = 4 # 加密线程数 innodb_encryption_rotate_key_age = 90 # 90 天轮换密钥
(1)创建加密密钥(需先设置密钥环插件)
-- 启用密钥环插件(my.cnf 中配置) [mysqld] early-plugin-load-add = keyring_file.so keyring_file_data = /var/lib/mysql-keyring/keyring # 密钥存储路径 -- 创建加密表(自动加密) create table appdb.user (id int, name varchar(20)) engine=innodb;
2. 敏感字段应用层加密
对密码、手机号、身份证号等敏感字段,在应用层加密后存储(避免数据库管理员直接查看):
- 推荐算法:aes-256-gcm(对称加密,需妥善保管密钥);
- 示例(mysql 内置 aes 加密,仅作演示,建议应用层加密):
-- 加密存储(密钥需保存在应用配置,而非数据库)
insert into appdb.user (id, phone) values (1, aes_encrypt('13800138000', 'app_aes_key_2025'));
-- 解密查询
select id, aes_decrypt(phone, 'app_aes_key_2025') as phone from appdb.user;
3. 定期备份 + 异地存储(防止数据丢失)
(1)备份策略
- 全量备份:每日 1 次(使用
mysqldump或 percona xtrabackup); - 增量备份:每小时 1 次(结合二进制日志
binlog); - 备份文件加密存储(如用
gpg加密)。
(2)mysqldump 备份示例(linux)
# 全量备份(含结构+数据,--master-data 记录 binlog 位置,用于增量备份) mysqldump -u root -p --all-databases --master-data=2 --single-transaction --quick --lock-tables=false > full_backup_$(date +%y%m%d).sql # 加密备份文件 gpg -c full_backup_20251113.sql # 输入密码加密,生成 .gpg 文件 # 复制到异地存储(如 ftp/oss/s3) scp full_backup_20251113.sql.gpg user@backup-server:/backup/mysql/
(3)关键要求
- 定期测试恢复流程(确保备份可用);
- 备份文件保留至少 30 天;
- 异地存储与生产环境物理隔离。
六、日志与审计加固(追溯安全事件)
1. 启用关键日志
(1)错误日志(记录启动 / 关闭 / 异常错误)
[mysqld] log-error = /var/log/mysql/mysqld-error.log log-error-verbosity = 3 # 详细日志级别
(2)慢查询日志(优化性能,间接防范恶意慢查询攻击)
[mysqld] slow_query_log = on slow_query_log_file = /var/log/mysql/slow.log long_query_time = 2 # 执行时间超过 2 秒的查询记录 log_queries_not_using_indexes = on # 记录未使用索引的查询
(3)二进制日志(binlog,用于增量备份 + 操作追溯)
[mysqld] server-id = 1 # 唯一服务器 id(主从复制/增量备份必需) log_bin = /var/log/mysql/mysql-bin # binlog 存储路径 binlog_format = row # 行级格式(更安全,避免 sql 注入篡改日志) expire_logs_days = 7 # binlog 保留 7 天(避免磁盘满)
2. 启用审计日志(mysql 企业版 / percona server)
社区版 mysql 无内置审计功能,需安装第三方插件(如 audit_log)或使用 percona server(内置审计插件):
# percona server 审计配置(my.cnf) [mysqld] plugin-load-add = audit_log.so audit_log_file = /var/log/mysql/audit.log audit_log_format = json # json 格式便于分析 audit_log_policy = all # 记录所有操作(可按需调整为 logins/ddl/dml)
3. 日志文件权限保护
# 修改日志目录权限(仅 mysql 用户可读) chown -r mysql:mysql /var/log/mysql chmod 700 /var/log/mysql chmod 600 /var/log/mysql/*
七、配置文件加固(my.cnf/my.ini)
汇总核心加固配置(直接替换或追加到 [mysqld] 段):
[mysqld] # 基础安全 bind-address = 192.168.1.100 local-infile = 0 symbolic-links = 0 # 禁用符号链接(防止目录遍历攻击) max_connections = 1000 # 限制最大连接数(防止dos攻击) wait_timeout = 600 # 空闲连接超时 10 分钟 interactive_timeout = 600 # 密码策略(5.7+) validate_password_length = 12 validate_password_policy = strong validate_password_special_char_count = 1 # ssl 加密(8.0+) ssl-ca = /etc/mysql/ssl/ca.pem ssl-cert = /etc/mysql/ssl/server-cert.pem ssl-key = /etc/mysql/ssl/server-key.pem require_secure_transport = on # 数据加密(8.0.16+) innodb_encrypt_tables = on innodb_encrypt_log = on early-plugin-load-add = keyring_file.so keyring_file_data = /var/lib/mysql-keyring/keyring # 日志配置 log-error = /var/log/mysql/mysqld-error.log slow_query_log = on 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 # 禁用危险功能 disable-log-bin = off # 启用 binlog(前面已配置,此处强调)
八、定期维护与监控
1. 定期安全检查
- 每月执行
mysql_secure_installation复查; - 每季度扫描 mysql 漏洞(使用工具如 nessus、openvas);
- 每半年更新 mysql 补丁(关注 oracle 安全公告)。
2. 监控关键指标
- 异常登录:监控
host为陌生 ip 的登录记录(查询mysql.general_log或审计日志); - 慢查询 / 大事务:通过
slow.log或监控工具(如 pmm、zabbix)预警; - 权限变更:定期对比
mysql.user表,发现未授权的用户 / 权限变更。
3. 应急响应预案
- 若发现数据泄露:立即禁用可疑账号、切断公网访问、备份当前数据、追溯攻击源;
- 若遭遇暴力破解:临时封禁攻击 ip(防火墙 / 安全组)、修改所有账号密码、启用二次验证(如结合 pam 插件)。
总结
mysql 加固核心是 “最小权限 + 加密传输 + 数据保护 + 审计追溯”,优先完成 mysql_secure_installation、防火墙限制、密码策略、禁用公网监听这 4 项基础操作,再逐步推进 ssl 加密、tde 存储加密、审计日志等高级防护。
根据业务场景灵活调整(如内网数据库可简化 ssl 配置,但必须限制登录 ip;公网数据库需强制 ssl + 二次验证),定期复查加固效果,确保安全策略持续有效。
到此这篇关于mysql全面安全加固实战的文章就介绍到这了,更多相关mysql安全加固内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论