MySQL教程 / 第 300 节

第30章:MySQL安全加固

构建安全的数据库环境

30.1 安全加固概述

30.1.1 安全威胁

常见威胁:

  • SQL注入攻击
  • 暴力破解
  • 权限滥用
  • 数据泄露
  • 拒绝服务攻击(DoS)

30.2 账户安全 ⭐⭐⭐⭐⭐

30.2.1 删除默认账户

删除匿名用户和测试数据库:

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

-- 删除匿名用户
DELETE FROM mysql.user WHERE user = '';

-- 删除test数据库
DROP DATABASE IF EXISTS test;

-- 刷新权限
FLUSH PRIVILEGES;

30.2.2 禁用root远程登录

只允许root本地登录:

-- 查看root用户
SELECT user, host FROM mysql.user WHERE user = 'root';

-- 删除root远程登录
DELETE FROM mysql.user WHERE user = 'root' AND host != 'localhost';

-- 或修改root只能本地登录
UPDATE mysql.user SET host = 'localhost' WHERE user = 'root';

FLUSH PRIVILEGES;

30.2.3 强密码策略

配置密码策略:

# my.cnf
[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

# 密码过期
default_password_lifetime = 90

# 密码重用限制
password_history = 5
password_reuse_interval = 365

修改用户密码:

-- 设置密码过期
ALTER USER 'app_user'@'localhost' PASSWORD EXPIRE INTERVAL 90 DAY;

-- 设置密码历史
ALTER USER 'app_user'@'localhost' PASSWORD HISTORY 5;

-- 设置密码重用间隔
ALTER USER 'app_user'@'localhost' PASSWORD REUSE INTERVAL 365 DAY;

30.2.4 限制登录失败次数

配置登录失败锁定:

-- MySQL 8.0.19+
ALTER USER 'app_user'@'localhost' 
FAILED_LOGIN_ATTEMPTS 3 
PASSWORD_LOCK_TIME 1;  -- 锁定1天

-- 解锁用户
ALTER USER 'app_user'@'localhost' ACCOUNT UNLOCK;

30.3 网络安全 ⭐⭐⭐⭐⭐

30.3.1 绑定IP地址

只监听内网IP:

# my.cnf
[mysqld]
bind-address = 192.168.1.10

# 或只监听本地
bind-address = 127.0.0.1

30.3.2 修改默认端口

修改默认端口(3306):

# my.cnf
[mysqld]
port = 13306

30.3.3 防火墙配置

配置防火墙:

# CentOS/RHEL
# 只允许指定IP访问MySQL
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.0/24" port protocol="tcp" port="3306" accept'
firewall-cmd --reload

# Ubuntu
# 只允许指定IP访问MySQL
ufw allow from 192.168.1.0/24 to any port 3306
ufw enable

30.4 SSL/TLS加密 ⭐⭐⭐⭐

30.4.1 生成SSL证书

生成证书:

# 使用mysql_ssl_rsa_setup生成证书(MySQL 5.7+)
mysql_ssl_rsa_setup --datadir=/var/lib/mysql

# 查看生成的证书
ls -l /var/lib/mysql/*.pem
# ca.pem:CA证书
# server-cert.pem:服务器证书
# server-key.pem:服务器私钥
# client-cert.pem:客户端证书
# client-key.pem:客户端私钥

30.4.2 配置SSL

服务器配置:

# my.cnf
[mysqld]
ssl-ca = /var/lib/mysql/ca.pem
ssl-cert = /var/lib/mysql/server-cert.pem
ssl-key = /var/lib/mysql/server-key.pem

# 要求所有连接使用SSL
require_secure_transport = ON

查看SSL状态:

-- 查看SSL变量
SHOW VARIABLES LIKE '%ssl%';

-- 查看当前连接是否使用SSL
SHOW STATUS LIKE 'Ssl_cipher';

30.4.3 要求用户使用SSL

创建要求SSL的用户:

-- 创建用户并要求SSL
CREATE USER 'secure_user'@'%' IDENTIFIED BY 'Password@123' REQUIRE SSL;

-- 修改现有用户要求SSL
ALTER USER 'app_user'@'%' REQUIRE SSL;

-- 要求X509证书
ALTER USER 'app_user'@'%' REQUIRE X509;

客户端连接:

# 使用SSL连接
mysql -u secure_user -p \
  --ssl-ca=/path/to/ca.pem \
  --ssl-cert=/path/to/client-cert.pem \
  --ssl-key=/path/to/client-key.pem

30.5 审计日志 ⭐⭐⭐⭐

30.5.1 开启审计日志

使用audit_log插件(MySQL Enterprise):

-- 安装插件
INSTALL PLUGIN audit_log SONAME 'audit_log.so';

-- 配置
SET GLOBAL audit_log_policy = ALL;
SET GLOBAL audit_log_format = JSON;

使用general_log(不推荐生产环境):

-- 开启general_log
SET GLOBAL general_log = ON;
SET GLOBAL general_log_file = '/var/log/mysql/general.log';

-- 查看日志
tail -f /var/log/mysql/general.log

30.5.2 监控可疑活动

监控登录失败:

# 查看错误日志中的登录失败
grep "Access denied" /var/log/mysql/error.log

30.6 数据加密 ⭐⭐⭐⭐

30.6.1 表空间加密

开启表空间加密(MySQL 5.7+):

-- 创建加密表
CREATE TABLE sensitive_data (
    id INT PRIMARY KEY,
    credit_card VARCHAR(100)
) ENCRYPTION = 'Y';

-- 修改现有表为加密表
ALTER TABLE users ENCRYPTION = 'Y';

配置加密密钥:

# my.cnf
[mysqld]
early-plugin-load = keyring_file.so
keyring_file_data = /var/lib/mysql-keyring/keyring

30.6.2 binlog加密

开启binlog加密(MySQL 8.0.14+):

SET GLOBAL binlog_encryption = ON;

30.7 SQL注入防护 ⭐⭐⭐⭐⭐

30.7.1 使用预处理语句

预处理语句(推荐):

-- ✅ 使用预处理语句(安全)
PREPARE stmt FROM 'SELECT * FROM users WHERE id = ?';
SET @id = 1;
EXECUTE stmt USING @id;

-- 应用程序中使用参数化查询
-- Java: PreparedStatement
-- Python: cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))
-- PHP: $stmt->bind_param("i", $user_id);

避免拼接SQL:

-- ❌ 不安全:SQL拼接
SELECT * FROM users WHERE name = 'admin' OR '1'='1';

-- ✅ 安全:预处理语句
PREPARE stmt FROM 'SELECT * FROM users WHERE name = ?';

30.8 安全配置清单

30.8.1 my.cnf安全配置

推荐配置:

[mysqld]
# 1. 网络安全
bind-address = 192.168.1.10
port = 13306

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

# 3. 密码策略
validate_password.policy = STRONG
validate_password.length = 12
default_password_lifetime = 90

# 4. 禁用危险功能
local_infile = OFF
skip-symbolic-links

# 5. 日志
log_error = /var/log/mysql/error.log
slow_query_log = ON
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2

# 6. 限制
max_connections = 500
max_connect_errors = 10

30.8.2 安全检查清单

检查项:

  • 删除匿名用户
  • 禁用root远程登录
  • 删除test数据库
  • 配置强密码策略
  • 绑定内网IP
  • 配置防火墙
  • 开启SSL/TLS
  • 最小权限原则
  • 定期备份
  • 监控审计日志
  • 禁用local_infile
  • 定期更新MySQL版本

30.9 本章总结

本章学习内容:

  • ✅ 安全加固概述
  • 账户安全(删除默认账户、强密码)⭐⭐⭐⭐⭐
  • 网络安全(绑定IP、防火墙)⭐⭐⭐⭐⭐
  • SSL/TLS加密⭐⭐⭐⭐
  • 审计日志⭐⭐⭐⭐
  • 数据加密⭐⭐⭐⭐
  • SQL注入防护⭐⭐⭐⭐⭐
  • ✅ 安全配置清单

重点掌握:

  1. 删除匿名用户和test数据库
  2. 禁用root远程登录
  3. 配置SSL/TLS
  4. 使用预处理语句防止SQL注入
  5. 最小权限原则

安全措施:

  • 账户安全:强密码、删除默认账户
  • 网络安全:绑定IP、防火墙、SSL
  • 数据安全:加密、备份
  • 审计:日志监控

面试重点:

  • 如何加固MySQL安全
  • 如何防止SQL注入
  • 如何配置SSL
  • 安全配置清单

下一章预告: 企业级实战案例


练习题

  1. 如何删除匿名用户?
  2. 如何禁用root远程登录?
  3. 如何配置强密码策略?
  4. 如何配置SSL/TLS?
  5. 如何防止SQL注入?
  6. 如何开启审计日志?
  7. 如何加密表数据?
  8. 安全配置清单有哪些?
  9. 如何限制登录失败次数?
  10. 实战:加固一个MySQL服务器

继续学习: 第31章:企业级实战案例