作为数据库管理员,我经历过多次安全事件后深刻认识到:数据库安全不是一次性任务,而是需要持续优化的过程。本文将分享我在生产环境中实施MySQL 8.4安全加固的完整方案,涵盖权限管理、审计日志、加密传输等核心环节。
即使是最新版本的MySQL,默认配置也无法满足企业级安全需求。去年我们某个业务数据库被入侵,攻击者正是利用了:
这次事件促使我们建立了完整的数据库安全体系。下面分享的具体方案已在金融、电商等多个行业的生产环境验证,符合等保2.0三级要求。
首先确认MySQL版本和关键组件:
bash复制# 查看MySQL版本(必须8.4+)
mysql -u root -p -e "SELECT VERSION();"
# 检查OpenSSL版本(需要3.0+)
openssl version
注意:CentOS 7等旧系统需要手动升级OpenSSL,否则无法支持TLS 1.3。建议使用MySQL官方提供的YUM源安装依赖。
执行以下检查脚本,生成安全基线报告:
sql复制-- 账号安全检查
SELECT user, host, plugin,
password_expired, account_locked
FROM mysql.user;
-- 权限审计
SELECT * FROM information_schema.USER_PRIVILEGES
WHERE PRIVILEGE_TYPE IN ('FILE','SUPER','SHUTDOWN');
-- 网络配置检查
SHOW VARIABLES LIKE 'have_ssl';
SHOW VARIABLES LIKE 'local_infile';
我们采用RBAC(基于角色的访问控制)模型,定义三类核心角色:
sql复制CREATE ROLE IF NOT EXISTS 'role_app_rw';
GRANT SELECT, INSERT, UPDATE, DELETE, EXECUTE
ON appdb.* TO 'role_app_rw';
sql复制CREATE ROLE IF NOT EXISTS 'role_app_ro';
GRANT SELECT ON appdb.* TO 'role_app_ro';
sql复制CREATE ROLE IF NOT EXISTS 'role_dba';
GRANT SELECT, INSERT, UPDATE, DELETE, CREATE,
DROP, INDEX, ALTER, CREATE VIEW, SHOW VIEW,
CREATE ROUTINE, ALTER ROUTINE, EXECUTE,
RELOAD, PROCESS, SHOW DATABASES
ON *.* TO 'role_dba';
为开发团队创建账号示例:
sql复制CREATE USER 'dev_user'@'192.168.1.%'
IDENTIFIED BY 'Dev@Secure2024!'
PASSWORD EXPIRE INTERVAL 90 DAY
FAILED_LOGIN_ATTEMPTS 5
PASSWORD_LOCK_TIME 1
REQUIRE SSL;
GRANT 'role_app_rw' TO 'dev_user'@'192.168.1.%';
SET DEFAULT ROLE 'role_app_rw' TO 'dev_user'@'192.168.1.%';
关键参数说明:
FAILED_LOGIN_ATTEMPTS 5:连续5次失败后锁定账号PASSWORD_LOCK_TIME 1:自动锁定1天REQUIRE SSL:强制SSL连接在my.cnf中设置:
ini复制[mysqld]
validate_password.policy = STRONG
validate_password.length = 12
validate_password.mixed_case_count = 1
validate_password.number_count = 1
validate_password.special_char_count = 1
validate_password.check_user_name = ON
sql复制-- 全局设置
SET GLOBAL default_password_lifetime = 90;
SET GLOBAL password_history = 6;
-- 特定账号豁免(如服务账号)
ALTER USER 'svc_account'@'%' PASSWORD EXPIRE NEVER;
bash复制# 生成CA证书
openssl genrsa 4096 > ca-key.pem
openssl req -new -x509 -nodes -days 3650 \
-key ca-key.pem -out ca-cert.pem \
-subj "/C=CN/ST=Beijing/O=YourCompany/CN=MySQL-CA"
# 生成服务端证书
openssl req -newkey rsa:4096 -nodes -days 3650 \
-keyout server-key.pem -out server-req.pem \
-subj "/C=CN/ST=Beijing/O=YourCompany/CN=mysql-server"
openssl x509 -req -in server-req.pem -days 3650 \
-CA ca-cert.pem -CAkey ca-key.pem -set_serial 01 \
-out server-cert.pem
ini复制[mysqld]
ssl_ca = /etc/mysql/ssl/ca-cert.pem
ssl_cert = /etc/mysql/ssl/server-cert.pem
ssl_key = /etc/mysql/ssl/server-key.pem
tls_version = TLSv1.2,TLSv1.3
require_secure_transport = ON
sql复制INSTALL PLUGIN audit_log SONAME 'audit_log.so';
-- 验证安装
SELECT PLUGIN_NAME, PLUGIN_STATUS
FROM information_schema.PLUGINS
WHERE PLUGIN_NAME = 'audit_log';
ini复制[mysqld]
audit_log_file = /var/log/mysql/audit.log
audit_log_format = JSON
audit_log_policy = ALL
audit_log_rotate_on_size = 1G
audit_log_strategy = ASYNCHRONOUS
生产建议:高频查询场景可设置
audit_log_policy = LOGINS,然后通过过滤规则精细控制审计范围。
bash复制# 允许应用服务器访问
firewall-cmd --permanent --add-rich-rule='
rule family="ipv4"
source address="192.168.1.0/24"
port protocol="tcp" port="3306" accept'
# 默认拒绝其他连接
firewall-cmd --permanent --remove-service=mysql
firewall-cmd --reload
ini复制[mysqld]
bind-address = 192.168.1.100
skip_name_resolve = ON
max_connections = 500
max_user_connections = 30
sql复制-- 连接失败统计
SHOW STATUS LIKE 'Connection_errors%';
-- SSL连接情况
SHOW STATUS LIKE 'Ssl%';
-- 审计日志状态
SELECT audit_log_filter_flush_status,
audit_log_rotate_status
FROM performance_schema.events_waits_current;
检查步骤:
bash复制# 测试SSL连接
mysql -u dev_user -p -h 192.168.1.100 \
--ssl-ca=/path/to/ca-cert.pem \
-e "SHOW STATUS LIKE 'Ssl_version';"
处理方法:
bash复制# 手动轮转日志
mysql -e "SELECT audit_log_rotate();"
# 日志压缩归档
find /var/log/mysql/ -name "audit.log.*" \
-mtime +7 -exec gzip {} \;
bash复制#!/bin/bash
# 每月执行一次权限审计
REPORT="/var/log/mysql/security_audit_$(date +%Y%m).log"
mysql -u root -p -e "
SELECT CONCAT(user,'@',host) AS account,
IF(password_expired='Y','YES','NO') AS expired,
IF(account_locked='Y','YES','NO') AS locked
FROM mysql.user
WHERE user NOT IN ('mysql.sys','mysql.infoschema')
" > $REPORT
建议每2年更新一次SSL证书,流程:
完成所有配置后,使用以下命令验证:
sql复制-- 基础安全项验证
SELECT '无匿名账号' AS item,
COUNT(*) = 0 AS pass
FROM mysql.user WHERE user = ''
UNION ALL
SELECT 'root远程登录',
COUNT(*) = 0
FROM mysql.user
WHERE user = 'root' AND host != 'localhost'
UNION ALL
SELECT 'SSL已启用',
VARIABLE_VALUE = 'YES'
FROM performance_schema.global_status
WHERE VARIABLE_NAME = 'Ssl_server_not_after';
实际部署中,我们发现最容易被忽视的是:
建议将这些检查项纳入日常巡检流程。通过以上措施,我们的数据库系统已连续18个月无安全事件发生。