Skip to content

MySQL 安全加固建议

权限管理

最小权限原则

加固措施

  1. 创建专用用户

    • 为每个应用创建独立的数据库用户
    • 为管理任务创建专用管理员用户
    • 避免使用 root 用户进行日常操作
  2. 精细权限控制

    • 只授予用户必要的权限
    • 使用最小权限组合
    • 定期审查和回收不必要的权限
  3. 权限分配示例

sql
-- 创建应用用户(只读权限)
CREATE USER 'app_read'@'%' IDENTIFIED BY 'strong_password';
GRANT SELECT ON app_db.* TO 'app_read'@'%';

-- 创建应用用户(读写权限)
CREATE USER 'app_write'@'%' IDENTIFIED BY 'strong_password';
GRANT SELECT, INSERT, UPDATE, DELETE ON app_db.* TO 'app_write'@'%';

-- 创建管理员用户(有限管理权限)
CREATE USER 'db_admin'@'localhost' IDENTIFIED BY 'strong_password';
GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, ALTER, INDEX ON *.* TO 'db_admin'@'localhost';

角色管理

加固措施

  1. 使用角色管理权限

    • 创建功能角色
    • 将权限分配给角色
    • 将角色分配给用户
  2. 角色管理示例

sql
-- 创建只读角色
CREATE ROLE 'read_only';
GRANT SELECT ON *.* TO 'read_only';

-- 创建读写角色
CREATE ROLE 'read_write';
GRANT SELECT, INSERT, UPDATE, DELETE ON *.* TO 'read_write';

-- 分配角色给用户
GRANT 'read_only' TO 'app_user'@'%';
SET DEFAULT ROLE 'read_only' TO 'app_user'@'%';

权限审计

加固措施

  1. 定期权限审计

    • 审查用户权限
    • 检查未使用的用户
    • 验证权限分配是否合理
  2. 审计工具

    • 使用 SHOW GRANTS 查看用户权限
    • 使用 mysql.user 表分析用户信息
    • 使用 mysql.role_edges 查看角色分配
  3. 审计示例

sql
-- 查看用户权限
SHOW GRANTS FOR 'app_user'@'%';

-- 查看所有用户
SELECT user, host FROM mysql.user;

-- 查看角色分配
SELECT FROM_USER, TO_USER, FROM_HOST, TO_HOST 
FROM mysql.role_edges;

密码策略

密码强度要求

加固措施

  1. 设置密码验证插件

    • 启用 validate_password 插件
    • 配置密码强度要求
    • 定期强制密码更改
  2. 密码策略配置

sql
-- 安装并启用密码验证插件
INSTALL PLUGIN validate_password SONAME 'validate_password.so';

-- 配置密码强度要求
SET GLOBAL validate_password_length = 12;
SET GLOBAL validate_password_number_count = 1;
SET GLOBAL validate_password_special_char_count = 1;
SET GLOBAL validate_password_mixed_case_count = 1;
SET GLOBAL validate_password_policy = 'STRONG';

-- 设置密码过期时间(90天)
SET GLOBAL default_password_lifetime = 90;

密码管理

加固措施

  1. 安全密码存储

    • 使用 caching_sha2_password 认证插件
    • 避免明文存储密码
    • 定期更新密码哈希
  2. 密码轮换

    • 实施密码轮换策略
    • 记录密码更改历史
    • 防止密码重用
  3. 密码管理示例

sql
-- 更改用户密码
ALTER USER 'app_user'@'%' IDENTIFIED BY 'new_strong_password';

-- 强制用户下次登录时更改密码
ALTER USER 'app_user'@'%' PASSWORD EXPIRE;

-- 禁用密码重用
SET GLOBAL password_history = 5;

认证插件

加固措施

  1. 使用安全认证插件

    • 优先使用 caching_sha2_password
    • 避免使用 mysql_native_password
    • 配置认证插件参数
  2. 认证插件配置

sql
-- 设置默认认证插件
SET GLOBAL default_authentication_plugin = 'caching_sha2_password';

-- 为用户指定认证插件
CREATE USER 'app_user'@'%' 
IDENTIFIED WITH caching_sha2_password BY 'strong_password';

网络安全

连接控制

加固措施

  1. 限制网络访问

    • 使用防火墙限制 MySQL 端口(3306)
    • 配置 bind-address 限制监听地址
    • 使用 skip-networking 禁用网络访问(仅本地访问时)
  2. 网络配置

sql
-- 限制监听地址(仅允许本地访问)
bind-address = 127.0.0.1

-- 或允许特定IP访问
bind-address = 192.168.1.100

-- 禁用网络访问(仅本地socket)
skip-networking

SSL/TLS 加密

加固措施

  1. 启用 SSL/TLS

    • 配置 SSL 证书
    • 强制使用 SSL 连接
    • 验证客户端证书
  2. SSL 配置

sql
-- SSL 配置
ssl-ca = /path/to/ca-cert.pem
ssl-cert = /path/to/server-cert.pem
ssl-key = /path/to/server-key.pem

-- 强制使用 SSL
require_secure_transport = ON

-- 为用户要求 SSL
CREATE USER 'app_user'@'%' 
IDENTIFIED BY 'strong_password'
REQUIRE SSL;

-- 为用户要求特定的 SSL 证书
CREATE USER 'secure_user'@'%' 
IDENTIFIED BY 'strong_password'
REQUIRE X509;

连接池安全

加固措施

  1. 连接池配置

    • 设置合理的连接超时
    • 配置连接验证
    • 限制最大连接数
  2. 连接池参数

sql
-- 设置连接超时
SET GLOBAL wait_timeout = 3600;
SET GLOBAL interactive_timeout = 3600;

-- 限制最大连接数
SET GLOBAL max_connections = 500;

-- 设置连接错误限制
SET GLOBAL max_connect_errors = 100;

数据加密

静态数据加密

加固措施

  1. 表空间加密

    • 启用 InnoDB 表空间加密
    • 配置加密密钥管理
    • 加密现有表空间
  2. 表空间加密配置

sql
-- 启用表空间加密
SET GLOBAL innodb_encrypt_tables = ON;
SET GLOBAL innodb_encrypt_log = ON;

-- 配置加密算法
SET GLOBAL innodb_crypto_algorithm = 'AES_256_GCM';

-- 加密现有表
ALTER TABLE sensitive_data ENCRYPTION='Y';

-- 创建加密表
CREATE TABLE encrypted_table (
    id INT PRIMARY KEY,
    data VARCHAR(255)
) ENCRYPTION='Y';

传输加密

加固措施

  1. 使用 SSL/TLS 传输加密

    • 配置服务器 SSL 证书
    • 强制客户端使用 SSL
    • 验证 SSL 连接
  2. 传输加密验证

sql
-- 验证 SSL 状态
SHOW VARIABLES LIKE '%ssl%';

-- 查看当前连接的 SSL 状态
SHOW STATUS LIKE 'Ssl_cipher';

-- 验证 SSL 连接
SELECT * FROM performance_schema.threads 
WHERE processlist_id = CONNECTION_ID()
AND ssl_version IS NOT NULL;

应用层加密

加固措施

  1. 敏感数据加密

    • 在应用层加密敏感数据
    • 使用安全的加密算法
    • 安全管理加密密钥
  2. 应用层加密示例(Python):

python
import cryptography
from cryptography.fernet import Fernet

# 生成密钥
key = Fernet.generate_key()
f = Fernet(key)

# 加密数据
sensitive_data = "credit_card_number"
encrypted_data = f.encrypt(sensitive_data.encode())

# 解密数据
decrypted_data = f.decrypt(encrypted_data).decode()

审计日志

审计日志配置

加固措施

  1. 启用审计日志

    • 配置 MySQL 审计日志
    • 设置审计日志格式
    • 配置审计日志轮换
  2. 审计日志配置

sql
-- 启用通用查询日志(仅用于调试)
SET GLOBAL general_log = ON;
SET GLOBAL general_log_file = '/var/log/mysql/general.log';

-- 启用错误日志
SET GLOBAL log_error = '/var/log/mysql/error.log';

-- 启用二进制日志(用于复制和恢复)
SET GLOBAL log_bin = '/var/log/mysql/binlog';
SET GLOBAL binlog_format = 'ROW';

-- 启用慢查询日志
SET GLOBAL slow_query_log = ON;
SET GLOBAL slow_query_log_file = '/var/log/mysql/slow-query.log';
SET GLOBAL long_query_time = 1;

审计插件

加固措施

  1. 使用审计插件

    • 安装 MySQL Enterprise Audit 插件
    • 或使用 MariaDB Audit Plugin
    • 配置审计规则
  2. 审计插件配置

sql
-- 安装 MariaDB Audit Plugin
INSTALL PLUGIN server_audit SONAME 'server_audit.so';

-- 配置审计事件
SET GLOBAL server_audit_events = 'CONNECT,QUERY,TABLE';

-- 配置审计日志文件
SET GLOBAL server_audit_log_file = '/var/log/mysql/audit.log';

-- 启用审计插件
SET GLOBAL server_audit_logging = ON;

日志管理

加固措施

  1. 日志安全管理

    • 限制日志文件权限
    • 加密敏感日志
    • 定期备份日志
    • 实施日志轮换
  2. 日志权限设置

bash
# 设置日志文件权限
chmod 640 /var/log/mysql/*.log
chown mysql:mysql /var/log/mysql/*.log

# 配置日志轮换(/etc/logrotate.d/mysql)
/var/log/mysql/*.log {
    daily
    rotate 7
    compress
    delaycompress
    missingok
    create 640 mysql mysql
    postrotate
        /usr/bin/mysqladmin flush-logs
    endscript
}

系统安全

文件系统安全

加固措施

  1. 文件权限

    • 限制 MySQL 数据目录权限
    • 保护配置文件
    • 限制日志文件访问
  2. 文件权限设置

bash
# 设置数据目录权限
chmod 750 /var/lib/mysql
chown mysql:mysql /var/lib/mysql

# 设置配置文件权限
chmod 644 /etc/my.cnf
chown mysql:mysql /etc/my.cnf

# 设置日志目录权限
chmod 750 /var/log/mysql
chown mysql:mysql /var/log/mysql

操作系统安全

加固措施

  1. 操作系统加固

    • 定期更新操作系统
    • 安装安全补丁
    • 配置防火墙
    • 禁用不必要的服务
  2. 防火墙配置

bash
# 配置防火墙允许 MySQL 端口
ufw allow 3306/tcp

# 或使用 iptables
iptables -A INPUT -p tcp --dport 3306 -s 192.168.1.0/24 -j ACCEPT
iptables -A INPUT -p tcp --dport 3306 -j DROP

进程安全

加固措施

  1. 运行用户

    • 使用专用的 MySQL 用户运行进程
    • 避免以 root 用户运行
    • 限制进程权限
  2. 进程安全配置

bash
# 检查 MySQL 运行用户
ps aux | grep mysql

# 确保 MySQL 以 mysql 用户运行
# 在 my.cnf 中配置
user = mysql

网络安全

防火墙配置

加固措施

  1. 配置防火墙

    • 限制 MySQL 端口访问
    • 只允许特定 IP 访问
    • 启用防火墙日志
  2. 防火墙规则

bash
# 使用 ufw 配置
ufw allow from 192.168.1.0/24 to any port 3306

# 使用 iptables 配置
iptables -A INPUT -p tcp --dport 3306 -s 192.168.1.0/24 -j ACCEPT
iptables -A INPUT -p tcp --dport 3306 -j LOG --log-prefix "MySQL Access Denied: "
iptables -A INPUT -p tcp --dport 3306 -j DROP

网络隔离

加固措施

  1. 网络隔离

    • 使用 VLAN 隔离数据库网络
    • 实施网络访问控制
    • 使用专用网络连接
  2. 连接控制

sql
-- 限制用户访问主机
CREATE USER 'app_user'@'192.168.1.%' IDENTIFIED BY 'password';

-- 限制管理员只能从本地访问
CREATE USER 'admin'@'localhost' IDENTIFIED BY 'password';

连接验证

加固措施

  1. 连接验证

    • 实施连接限制
    • 配置连接超时
    • 监控异常连接
  2. 连接限制

sql
-- 设置连接错误限制
SET GLOBAL max_connect_errors = 100;

-- 设置连接超时
SET GLOBAL wait_timeout = 3600;
SET GLOBAL interactive_timeout = 3600;

-- 限制每个用户的连接数
SET GLOBAL max_user_connections = 100;

安全更新和补丁

定期更新

加固措施

  1. 定期更新 MySQL

    • 关注 MySQL 安全公告
    • 定期应用安全补丁
    • 测试更新后再部署
  2. 更新流程

    • 备份数据库
    • 在测试环境测试更新
    • 计划更新时间窗口
    • 执行更新
    • 验证更新结果

漏洞管理

加固措施

  1. 漏洞扫描

    • 定期扫描 MySQL 漏洞
    • 使用专业漏洞扫描工具
    • 及时修复发现的漏洞
  2. 漏洞监控

    • 订阅 MySQL 安全公告
    • 关注 CVE 数据库
    • 参与安全社区
  3. 漏洞扫描工具

    • OpenVAS
    • Nessus
    • MySQL Enterprise Monitor

应急响应

安全事件处理

加固措施

  1. 安全事件响应计划

    • 制定安全事件响应流程
    • 明确角色和责任
    • 建立通信渠道
    • 定期演练
  2. 事件响应步骤

    • 检测和识别安全事件
    • 遏制事件影响
    • 消除事件根源
    • 恢复系统正常运行
    • 分析和学习

备份和恢复

加固措施

  1. 定期备份

    • 执行完整备份
    • 执行增量备份
    • 验证备份完整性
  2. 备份策略

bash
# 完整备份
mysqldump --all-databases --single-transaction --routines --triggers > full_backup.sql

# 增量备份(使用二进制日志)
mysqlbinlog --start-position=107 --stop-position=200 /var/log/mysql/binlog.000001 > incremental_backup.sql

# 验证备份
mysqlcheck --all-databases
  1. 恢复测试
    • 定期测试备份恢复
    • 验证恢复时间
    • 确保恢复数据完整

安全最佳实践

配置最佳实践

推荐配置

  1. 安全配置示例
ini
# MySQL 安全配置

[mysqld]
# 基础安全
user = mysql
bind-address = 127.0.0.1
skip-networking = 0

# 权限管理
local_infile = 0
secure_file_priv = /tmp

# 密码策略
validate_password_length = 12
validate_password_policy = STRONG
default_password_lifetime = 90
password_history = 5

# 审计日志
general_log = 0
slow_query_log = 1
long_query_time = 1
log_error = /var/log/mysql/error.log

# SSL/TLS
ssl-ca = /etc/mysql/ssl/ca-cert.pem
ssl-cert = /etc/mysql/ssl/server-cert.pem
ssl-key = /etc/mysql/ssl/server-key.pem
require_secure_transport = ON

# 数据加密
innodb_encrypt_tables = ON
innodb_encrypt_log = ON
innodb_crypto_algorithm = AES_256_GCM

# 连接控制
max_connections = 500
max_connect_errors = 100
wait_timeout = 3600
interactive_timeout = 3600

# 二进制日志
log_bin = /var/log/mysql/binlog
binlog_format = ROW
expire_logs_days = 7

操作最佳实践

推荐操作

  1. 日常操作安全

    • 使用专用管理工具
    • 避免在命令行中使用明文密码
    • 启用会话超时
    • 记录管理操作
  2. 安全操作示例

bash
# 使用 mysql_config_editor 存储密码
mysql_config_editor set --login-path=client --host=localhost --user=admin --password

# 使用登录路径连接
mysql --login-path=client

# 启用会话超时
mysql --connect-timeout=30 --wait-timeout=3600

监控最佳实践

推荐监控

  1. 安全监控

    • 监控异常连接
    • 监控权限变更
    • 监控敏感操作
    • 监控登录失败
  2. 监控工具

    • MySQL Enterprise Monitor
    • Percona Monitoring and Management
    • Prometheus + Grafana
    • 自定义监控脚本
  3. 监控示例

sql
-- 监控登录失败
SELECT * FROM performance_schema.host_cache 
WHERE SUM_CONNECT_ERRORS > 0;

-- 监控权限变更
SELECT * FROM mysql.general_log 
WHERE command_type = 'GRANT' OR command_type = 'REVOKE';

-- 监控异常连接
SELECT * FROM information_schema.processlist 
WHERE time > 600;

常见问题(FAQ)

Q1:如何保护 MySQL 根用户密码?

A1

  • 使用 mysql_config_editor 存储密码
  • 避免在脚本中硬编码密码
  • 定期更改根密码
  • 限制根用户只能从本地访问

Q2:如何检测 MySQL 安全漏洞?

A2

  • 使用专业漏洞扫描工具
  • 定期检查 MySQL 版本
  • 关注 MySQL 安全公告
  • 扫描系统漏洞

Q3:如何防止 SQL 注入攻击?

A3

  • 使用参数化查询
  • 实施输入验证
  • 使用最小权限原则
  • 启用 MySQL 查询重写

Q4:如何保护敏感数据?

A4

  • 使用表空间加密
  • 在应用层加密敏感数据
  • 实施访问控制
  • 审计敏感数据访问

Q5:如何应对 MySQL 安全事件?

A5

  • 执行应急响应计划
  • 隔离受影响的系统
  • 保存事件证据
  • 恢复系统从备份
  • 分析事件原因并改进

Q6:如何确保 MySQL 备份安全?

A6

  • 加密备份文件
  • 限制备份文件访问权限
  • 存储备份在安全位置
  • 定期测试备份恢复
  • 实施备份轮换策略