1. 首页 > MySQL教程 > 正文

MySQL教程FG191-MySQL安全防护体系概述

内容简介:MySQL安全防护体系是数据库运维的重要组成部分,对于保障数据的机密性、完整性和可用性至关重要。本文风哥教程参考MySQL官方文档和业界最佳实践,详细介绍MySQL安全防护体系的各个方面,包括认证、授权、加密、审计、访问控制等,并提供详细的实战案例和命令输出,帮助读者建立完善的MySQL安全防护体系。学习交流加群风哥微信:
itpux-com

Part01-基础概念与理论知识

1.1 安全防护体系概述

MySQL安全防护体系是一个多层次、全方位的安全保障体系,包括以下几个方面:

  • 认证(Authentication):验证用户身份,确保只有合法用户才能访问数据库
  • 授权(Authorization):控制用户对数据库对象的访问权限,确保用户只能访问其被授权的资源
  • 加密(Encryption):保护数据的机密性,包括数据传输加密和数据存储加密
  • 审计(Audit):记录数据库活动,便于安全审计和故障排查
  • 访问控制(Access Control):限制用户对数据库的访问,包括网络访问控制和资源访问控制
  • 漏洞管理(Vulnerability Management):及时发现和修复安全漏洞,确保系统的安全性
  • 安全监控(Security Monitoring):实时监控数据库活动,及时发现和响应安全事件

1.2 安全威胁

MySQL数据库面临的安全威胁主要包括:

  • 未授权访问:非法用户通过猜测密码、SQL注入等方式获取数据库访问权限
  • 数据泄露:敏感数据被非法获取或泄露
  • 数据篡改:数据被非法修改或删除
  • 拒绝服务攻击:通过大量请求或恶意操作导致数据库无法正常服务
  • SQL注入:通过在输入中插入恶意SQL代码,执行未授权的数据库操作
  • 特权提升:普通用户通过漏洞获取管理员权限
  • 配置不当:安全配置参数设置不合理,导致安全漏洞
  • 社会工程学攻击:通过欺骗、诱导等方式获取敏感信息

1.3 安全防护原则

MySQL安全防护应遵循以下原则:

  • 最小权限原则:只授予用户完成其工作所需的最小权限,避免权限滥用
  • 分层防御原则:采用多层次的安全防护措施,提高系统的安全性
  • 定期审计原则:定期进行安全审计,及时发现和修复安全漏洞
  • 数据加密原则:对敏感数据进行加密存储和传输,保护数据的机密性
  • 访问控制原则:严格控制用户对数据库的访问,包括网络访问和资源访问
  • 安全更新原则:及时更新MySQL版本和应用安全补丁,修复已知漏洞
  • 备份恢复原则:建立完善的备份恢复策略,确保数据的可用性和可恢复性
  • 安全培训原则:对数据库管理员和用户进行安全培训,提高安全意识
安全防护建议:建立完善的MySQL安全防护体系,需要综合考虑认证、授权、加密、审计、访问控制等多个方面,采取多层次的安全防护措施,确保数据库的安全性。

Part02-生产环境规划与建议

2.1 安全架构规划

MySQL安全架构规划包括以下几个方面:

2.1.1 网络安全架构

  • 网络隔离:将MySQL服务器与其他服务器进行网络隔离,提高安全性
  • 防火墙配置:配置防火墙规则,限制对MySQL端口的访问
  • VPN连接:使用VPN连接访问MySQL服务器,保护数据传输的安全性
  • 负载均衡:使用负载均衡设备或软件,分发客户端请求,提高系统性能和可用性

2.1.2 服务器安全架构

  • 操作系统安全:配置操作系统安全参数,如关闭不必要的服务、限制用户权限等
  • MySQL安装安全:使用官方源安装MySQL,确保软件的完整性和安全性
  • MySQL配置安全:配置MySQL安全参数,如禁用远程root登录、启用密码验证插件等
  • 数据存储安全:使用加密存储设备,保护数据的物理安全

2.1.3 应用安全架构

  • 应用程序安全:编写安全的应用程序代码,避免SQL注入、XSS等安全漏洞
  • 连接池配置:配置合理的连接池参数,避免连接泄露和资源耗尽
  • ORM框架使用:使用ORM框架,避免直接拼接SQL语句,减少SQL注入风险
  • 输入验证:对用户输入进行严格验证,避免恶意输入

2.2 安全策略制定

MySQL安全策略制定包括以下几个方面:

2.2.1 密码策略

  • 密码复杂度:要求用户使用复杂密码,包括大小写字母、数字和特殊字符
  • 密码长度:要求密码长度不少于8个字符
  • 密码过期:设置密码过期时间,要求用户定期更换密码
  • 密码历史:限制用户重用之前使用过的密码

2.2.2 权限策略

  • 最小权限原则:只授予用户完成其工作所需的最小权限
  • 权限分离:将不同的权限分配给不同的用户,避免权限集中
  • 定期权限审计:定期审计用户权限,及时撤销不必要的权限
  • 角色管理:使用角色管理权限,提高权限管理的效率

2.2.3 审计策略

  • 审计日志配置:配置审计日志,记录数据库活动
  • 审计日志保留:设置审计日志保留时间,便于安全审计和故障排查
  • 审计日志分析:定期分析审计日志,及时发现和响应安全事件
  • 审计日志安全:保护审计日志的安全性,避免日志被篡改或删除

2.3 安全合规要求

MySQL安全合规要求包括以下几个方面:

2.3.1 数据保护法规

  • GDPR:欧盟通用数据保护条例,要求保护个人数据的安全性和隐私性
  • CCPA:加州消费者隐私法案,要求保护消费者的个人数据
  • 网络安全法:中国网络安全法,要求保护网络和数据的安全性
  • 等保2.0:中国信息安全等级保护制度2.0,要求对信息系统进行等级保护

2.3.2 行业合规要求

  • PCI DSS:支付卡行业数据安全标准,要求保护支付卡数据的安全性
  • HIPAA:健康保险流通与责任法案,要求保护医疗健康数据的安全性
  • SOX:萨班斯-奥克斯利法案,要求保护财务数据的准确性和完整性
  • ISO 27001:信息安全管理体系标准,要求建立完善的信息安全管理体系
风哥提示:生产环境安全规划是MySQL安全防护的基础,需要根据业务需求和合规要求,制定详细的安全策略和架构规划,确保数据库的安全性和合规性。

Part03-生产环境项目实施方案

3.1 认证管理

MySQL认证管理是确保只有合法用户才能访问数据库的重要措施,包括以下几个方面:

# 1. 用户管理
# 创建用户
mysql> CREATE USER ‘app_user’@’192.168.1.%’ IDENTIFIED BY ‘secure_password’;
Query OK, 0 rows affected (0.01 sec)

# 修改用户密码
mysql> ALTER USER ‘app_user’@’192.168.1.%’ IDENTIFIED BY ‘new_secure_password’;
Query OK, 0 rows affected (0.01 sec)

# 删除用户
mysql> DROP USER ‘app_user’@’192.168.1.%’;
Query OK, 0 rows affected (0.01 sec)

# 查看用户
mysql> SELECT User, Host FROM mysql.user;
+——————+—————+
| User | Host |
+——————+—————+
| root | localhost |
| mysql.infoschema | localhost |
| mysql.session | localhost |
| mysql.sys | localhost |
| app_user | 192.168.1.% |
+——————+—————+

# 2. 密码策略配置
# 安装密码验证插件
mysql> INSTALL PLUGIN validate_password SONAME ‘validate_password.so’;
Query OK, 0 rows affected (0.00 sec)

# 查看密码验证插件状态
mysql> SHOW PLUGINS LIKE ‘validate_password’;
+——————-+———-+——————–+———————-+———+
| Name | Status | Type | Library | License |
+——————-+———-+——————–+———————-+———+
| validate_password | ACTIVE | VALIDATE PASSWORD | validate_password.so | GPL |
+——————-+———-+——————–+———————-+———+

# 设置密码策略
mysql> SET GLOBAL validate_password.policy = ‘MEDIUM’;
Query OK, 0 rows affected (0.00 sec)

mysql> SET GLOBAL validate_password.length = 8;
Query OK, 0 rows affected (0.00 sec)

mysql> SET GLOBAL validate_password.mixed_case_count = 1;
Query OK, 0 rows affected (0.00 sec)

mysql> SET GLOBAL validate_password.number_count = 1;
Query OK, 0 rows affected (0.00 sec)

mysql> SET GLOBAL validate_password.special_char_count = 1;
Query OK, 0 rows affected (0.00 sec)

# 查看密码策略配置
mysql> SHOW VARIABLES LIKE ‘validate_password%’;
+————————————–+——–+
| Variable_name | Value |
+————————————–+——–+
| validate_password.check_user_name | ON |
| validate_password.dictionary_file | |
| validate_password.length | 8 |
| validate_password.mixed_case_count | 1 |
| validate_password.number_count | 1 |
| validate_password.policy | MEDIUM |
| validate_password.special_char_count | 1 |
+————————————–+——–+

# 3. 身份验证插件
# 查看支持的身份验证插件
mysql> SHOW PLUGINS LIKE ‘auth%’;
+———————–+———-+——————–+———————-+———+
| Name | Status | Type | Library | License |
+———————–+———-+——————–+———————-+———+
| auth_socket | ACTIVE | AUTHENTICATION | auth_socket.so | GPL |
| auth_sha256_password | ACTIVE | AUTHENTICATION | auth_sha256_password.so | GPL |
| auth_gssapi_client | ACTIVE | CLIENT_AUTHENTICATION | auth_gssapi_client.so | GPL |
| auth_gssapi_server | ACTIVE | AUTHENTICATION | auth_gssapi_server.so | GPL |
| auth_pam_client | ACTIVE | CLIENT_AUTHENTICATION | auth_pam_client.so | GPL |
| auth_pam_server | ACTIVE | AUTHENTICATION | auth_pam_server.so | GPL |
| auth_test_plugin | DISABLED | AUTHENTICATION | auth_test_plugin.so | GPL |
+———————–+———-+——————–+———————-+———+

# 创建使用特定身份验证插件的用户
mysql> CREATE USER ‘pam_user’@’localhost’ IDENTIFIED WITH auth_pam;
Query OK, 0 rows affected (0.01 sec)

# 4. 双因素认证
# 安装双因素认证插件
# 参考:https://dev.mysql.com/doc/refman/8.4/en/pam-authentication-plugin.html

# 5. 密码过期策略
# 设置用户密码过期
mysql> ALTER USER ‘app_user’@’192.168.1.%’ PASSWORD EXPIRE;
Query OK, 0 rows affected (0.01 sec)

# 设置密码过期时间
mysql> SET GLOBAL default_password_lifetime = 90;
Query OK, 0 rows affected (0.00 sec)

# 查看密码过期时间
mysql> SHOW VARIABLES LIKE ‘default_password_lifetime’;
+—————————+——-+
| Variable_name | Value |
+—————————+——-+
| default_password_lifetime | 90 |
+—————————+——-+

3.2 授权管理

MySQL授权管理是控制用户对数据库对象访问权限的重要措施,包括以下几个方面:

# 1. 权限授予
# 授予数据库级权限
mysql> GRANT SELECT, INSERT, UPDATE, DELETE ON fgedudb.* TO ‘app_user’@’192.168.1.%’;
Query OK, 0 rows affected (0.01 sec)

# 授予表级权限
mysql> GRANT SELECT, INSERT ON fgedudb.fgedu_users TO ‘app_user’@’192.168.1.%’;
Query OK, 0 rows affected (0.01 sec)

# 授予列级权限
mysql> GRANT SELECT (id, name, email) ON fgedudb.fgedu_users TO ‘app_user’@’192.168.1.%’;
Query OK, 0 rows affected (0.01 sec)

# 授予管理权限
mysql> GRANT ALL PRIVILEGES ON *.* TO ‘admin_user’@’localhost’ WITH GRANT OPTION;
Query OK, 0 rows affected (0.01 sec)

# 2. 权限撤销
# 撤销数据库级权限
mysql> REVOKE DELETE ON fgedudb.* FROM ‘app_user’@’192.168.1.%’;
Query OK, 0 rows affected (0.01 sec)

# 撤销表级权限
mysql> REVOKE INSERT ON fgedudb.fgedu_users FROM ‘app_user’@’192.168.1.%’;
Query OK, 0 rows affected (0.01 sec)

# 撤销所有权限
mysql> REVOKE ALL PRIVILEGES ON fgedudb.* FROM ‘app_user’@’192.168.1.%’;
Query OK, 0 rows affected (0.01 sec)

# 3. 查看权限
# 查看用户权限
mysql> SHOW GRANTS FOR ‘app_user’@’192.168.1.%’;
+———————————————————————-+
| Grants for app_user@192.168.1.% |
+———————————————————————-+
| GRANT USAGE ON *.* TO `app_user`@`192.168.1.%` |
| GRANT SELECT, INSERT, UPDATE ON `fgedudb`.* TO `app_user`@`192.168.1.%` |
+———————————————————————-+

# 查看当前用户权限
mysql> SHOW GRANTS;
+———————————————————————-+
| Grants for root@localhost |
+———————————————————————-+
| GRANT ALL PRIVILEGES ON *.* TO `root`@`localhost` WITH GRANT OPTION |
| GRANT PROXY ON ”@” TO `root`@`localhost` WITH GRANT OPTION |
+———————————————————————-+

# 4. 角色管理
# 创建角色
mysql> CREATE ROLE ‘read_only’, ‘read_write’, ‘admin’;
Query OK, 0 rows affected (0.01 sec)

# 授予角色权限
mysql> GRANT SELECT ON *.* TO ‘read_only’;
Query OK, 0 rows affected (0.01 sec)

mysql> GRANT SELECT, INSERT, UPDATE, DELETE ON *.* TO ‘read_write’;
Query OK, 0 rows affected (0.01 sec)

mysql> GRANT ALL PRIVILEGES ON *.* TO ‘admin’ WITH GRANT OPTION;
Query OK, 0 rows affected (0.01 sec)

# 分配角色给用户
mysql> GRANT ‘read_write’ TO ‘app_user’@’192.168.1.%’;
Query OK, 0 rows affected (0.01 sec)

# 设置默认角色
mysql> SET DEFAULT ROLE ‘read_write’ FOR ‘app_user’@’192.168.1.%’;
Query OK, 0 rows affected (0.01 sec)

# 激活角色
mysql> SET ROLE ‘read_write’;
Query OK, 0 rows affected (0.00 sec)

# 查看角色
mysql> SELECT * FROM mysql.role_edges;
+———–+———–+———+———+——————-+——————-+
| FROM_HOST | FROM_USER | TO_HOST | TO_USER | WITH_ADMIN_OPTION | GRANTEE_PRIVILEGES |
+———–+———–+———+———+——————-+——————-+
| % | app_user | % | read_write | N | NULL |
+———–+———–+———+———+——————-+——————-+

# 5. 权限继承
# 创建用户组角色
mysql> CREATE ROLE ‘sales_team’;
Query OK, 0 rows affected (0.01 sec)

# 授予用户组角色权限
mysql> GRANT SELECT ON sales_db.* TO ‘sales_team’;
Query OK, 0 rows affected (0.01 sec)

# 创建用户并分配用户组角色
mysql> CREATE USER ‘sales_user1’@’%’ IDENTIFIED BY ‘password’ DEFAULT ROLE ‘sales_team’;
Query OK, 0 rows affected (0.01 sec)

mysql> CREATE USER ‘sales_user2’@’%’ IDENTIFIED BY ‘password’ DEFAULT ROLE ‘sales_team’;
Query OK, 0 rows affected (0.01 sec)

# 授予用户组角色额外权限
mysql> GRANT INSERT ON sales_db.orders TO ‘sales_team’;
Query OK, 0 rows affected (0.01 sec)

# 6. 权限审计
# 查看权限变更记录
mysql> SELECT
THREAD_ID,
EVENT_ID,
TIMER_START,
SQL_TEXT
FROM performance_schema.events_statements_history
WHERE SQL_TEXT LIKE ‘%GRANT%’ OR SQL_TEXT LIKE ‘%REVOKE%’
ORDER BY TIMER_START DESC
LIMIT 10;
+———–+———-+—————-+——————————————————-+
| THREAD_ID | EVENT_ID | TIMER_START | SQL_TEXT |
+———–+———-+—————-+——————————————————-+
| 123 | 456 | 100000000000000 | GRANT SELECT ON fgedudb.* TO ‘app_user’@’192.168.1.%’ |
| 123 | 457 | 100000000000001 | REVOKE DELETE ON fgedudb.* FROM ‘app_user’@’192.168.1.%’ |
+———–+———-+—————-+——————————————————-+

3.3 加密配置

MySQL加密配置是保护数据机密性的重要措施,包括以下几个方面:

# 1. SSL/TLS配置
# 生成SSL证书
$ mkdir -p /mysql/ssl
$ cd /mysql/ssl

# 生成CA证书
$ 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 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 x509 -req -in client-req.pem -days 3650 -CA ca.pem -CAkey ca-key.pem -set_serial 02 >
client-cert.pem

# 验证证书
$ openssl verify -CAfile ca.pem server-cert.pem client-cert.pem
server-cert.pem: OK
client-cert.pem: OK

# 配置MySQL使用SSL
$ vi /etc/my.cnf
[mysqld]
ssl-ca = /mysql/ssl/ca.pem
ssl-cert = /mysql/ssl/server-cert.pem
ssl-key = /mysql/ssl/server-key.pem

# 要求加密连接
require_secure_transport = ON

# 重启MySQL服务
$ systemctl restart mysqld

# 查看SSL配置
mysql> SHOW VARIABLES LIKE ‘%ssl%’;
+————————————-+——————————–+——————-+
| Variable_name | Value | Variable_source |
+————————————-+——————————–+——————-+
| have_openssl | YES | COMPILED |
| have_ssl | YES | COMPILED |
| ssl_ca | /mysql/ssl/ca.pem | MYSQL_CONFIG |
| ssl_capath | | MYSQL_CONFIG |
| ssl_cert | /mysql/ssl/server-cert.pem | MYSQL_CONFIG |
| ssl_cipher | | MYSQL_CONFIG |
| ssl_crl | | MYSQL_CONFIG |
| ssl_crlpath | | MYSQL_CONFIG |
| ssl_key | /mysql/ssl/server-key.pem | MYSQL_CONFIG |
| require_secure_transport | ON | MYSQL_CONFIG |
+————————————-+——————————–+——————-+

# 测试SSL连接
$ mysql -u root -p –ssl-ca=/mysql/ssl/ca.pem –ssl-cert=/mysql/ssl/client-cert.pem
–ssl-key=/mysql/ssl/client-key.pem

mysql> SHOW STATUS LIKE ‘Ssl_cipher’;
+—————+—————————+
| Variable_name | Value |
+—————+—————————+
| Ssl_cipher | TLS_AES_256_GCM_SHA384 |
+—————+—————————+

# 2. 数据存储加密
# 查看InnoDB加密支持
mysql> SHOW VARIABLES LIKE ‘innodb_encrypt%’;
+———————————-+——-+——————-+
| Variable_name | Value | Variable_source |
+———————————-+——-+——————-+
| innodb_encrypt_log | OFF | MYSQL_CONFIG |
| innodb_encrypt_log_archive | OFF | MYSQL_CONFIG |
| innodb_encrypt_tables | OFF | MYSQL_CONFIG |
| innodb_encrypt_temporary_tables | OFF | MYSQL_CONFIG |
| innodb_encryption_rotate_key_age | 1 | MYSQL_CONFIG |
| innodb_encryption_rotation_iops | 100 | MYSQL_CONFIG |
+———————————-+——-+——————-+

# 启用InnoDB表空间加密
$ vi /etc/my.cnf
[mysqld]
innodb_encrypt_tables = ON
innodb_encrypt_log = ON
innodb_encrypt_temporary_tables = ON
innodb_encryption_threads = 4

# 创建加密表
mysql> CREATE TABLE fgedudb.encrypted_table (
id INT PRIMARY KEY AUTO_INCREMENT,
sensitive_data VARCHAR(255) NOT NULL
) ENCRYPTION=’Y’;
Query OK, 0 rows affected (0.01 sec)

# 查看表加密状态
mysql> SELECT TABLE_SCHEMA, TABLE_NAME, CREATE_OPTIONS FROM information_schema.TABLES WHERE TABLE_NAME =
‘encrypted_table’;
+————–+——————+—————-+——————-+
| TABLE_SCHEMA | TABLE_NAME | CREATE_OPTIONS | Variable_source |
+————–+——————+—————-+——————-+
| fgedudb | encrypted_table | ENCRYPTION=”Y” | NULL |
+————–+——————+—————-+——————-+

# 3. 列级加密
# 使用AES加密函数
mysql> INSERT INTO fgedudb.encrypted_table (sensitive_data) VALUES (AES_ENCRYPT(‘secret_data’,
‘encryption_key’));
Query OK, 1 row affected (0.00 sec)

# 使用AES解密函数
mysql> SELECT id, AES_DECRYPT(sensitive_data, ‘encryption_key’) AS decrypted_data FROM
fgedudb.encrypted_table;
+—-+—————-+——————-+
| id | decrypted_data | Variable_source |
+—-+—————-+——————-+
| 1 | secret_data | NULL |
+—-+—————-+——————-+

# 使用SHA256哈希函数
mysql> INSERT INTO fgedudb.users (username, password_hash) VALUES (‘user1’, SHA2(‘password123’, 256));
Query OK, 1 row affected (0.01 sec)

# 验证密码
mysql> SELECT * FROM fgedudb.users WHERE username = ‘user1’ AND password_hash = SHA2(‘password123’, 256);
+—-+———-+——————————————————————+
| id | username | password_hash |
+—-+———-+——————————————————————+
| 1 | user1 | a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3 |
+—-+———-+——————————————————————+

# 4. 密钥管理
# 配置密钥环插件
$ vi /etc/my.cnf
[mysqld]
early-plugin-load = keyring_file.so
keyring_file_data = /mysql/keyring/keyring-file

# 创建密钥环目录
$ mkdir -p /mysql/keyring
$ chown -R mysql:mysql /mysql/keyring

# 重启MySQL服务
$ systemctl restart mysqld

# 查看密钥环插件状态
mysql> SHOW PLUGINS LIKE ‘keyring%’;
+——————-+———-+——————–+———————-+———+
| Name | Status | Type | Library | License |
+——————-+———-+——————–+———————-+———+
| keyring_file | ACTIVE | KEYRING | keyring_file.so | GPL |
+——————-+———-+——————–+———————-+———+

# 创建加密密钥
mysql> CREATE TABLESPACE encrypted_ts ADD DATAFILE ‘encrypted_ts.ibd’ ENCRYPTION=’Y’;
Query OK, 0 rows affected (0.01 sec)

# 查看加密密钥
mysql> SELECT * FROM information_schema.INNODB_TABLESPACES_ENCRYPTION;
+————+——————–+—————————-+—————–+————–+————+————+————–+—————-+—————————-+
| SPACE | NAME | ENCRYPTION_SCHEME | KEY_SERVER_ID | KEY_ID | KEY_ROTATION_PAGE_NUMBER | STATE |
AUTO_EXTEND_SIZE | CURRENT_KEY_VERSION | ROTATING_OR_FLUSHING_PAGE_NUMBER |
+————+——————–+—————————-+—————–+————–+————+————+————–+—————-+—————————-+
| 4294967294 | mysql/plugin | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL |
| 4294967293 | mysql/innodb_ddl_ | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL |
| 4294967292 | mysql/innodb_redo_ | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL |
| 1 | mysql/innodb_index_stats | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL |
| 2 | mysql/innodb_table_stats | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL |
| 3 | mysql/gtid_executed | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL |
| 4 | fgedudb/fgedu_users | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL |
| 5 | encrypted_ts | AES_256_CTR | 1 | 1 | 0 | ENCRYPTED | 64 | 1 | NULL |
+————+——————–+—————————-+—————–+————–+————+————+————–+—————-+—————————-+

3.4 审计日志

MySQL审计日志是记录数据库活动的重要措施,便于安全审计和故障排查,包括以下几个方面:

# 1. 审计日志配置
# 安装审计日志插件
mysql> INSTALL PLUGIN audit_log SONAME ‘audit_log.so’;
Query OK, 0 rows affected (0.01 sec)

# 查看审计日志插件状态
mysql> SHOW PLUGINS LIKE ‘audit_log’;
+—————+———-+——————–+———————-+———+
| Name | Status | Type | Library | License |
+—————+———-+——————–+———————-+———+
| audit_log | ACTIVE | AUDIT | audit_log.so | GPL |
+—————+———-+——————–+———————-+———+

# 配置审计日志
$ vi /etc/my.cnf
[mysqld]
audit_log_format = JSON
audit_log_file = /mysql/logs/audit.log
audit_log_policy = ALL
audit_log_rotate_on_size = 104857600 # 100MB
audit_log_rotations = 10
audit_log_include_accounts = ‘app_user@192.168.1.%’
audit_log_exclude_accounts = ‘root@localhost’

# 重启MySQL服务
$ systemctl restart mysqld

# 查看审计日志配置
mysql> SHOW VARIABLES LIKE ‘audit_log%’;
+—————————–+——————————–+——————-+
| Variable_name | Value | Variable_source |
+—————————–+——————————–+——————-+
| audit_log_buffer_size | 1048576 | MYSQL_CONFIG |
| audit_log_connection_policy | ALL | MYSQL_CONFIG |
| audit_log_current_session | ON | MYSQL_CONFIG |
| audit_log_database_engine | OFF | MYSQL_CONFIG |
| audit_log_exclude_accounts | root@localhost | MYSQL_CONFIG |
| audit_log_exclude_databases | | MYSQL_CONFIG |
| audit_log_exclude_events | | MYSQL_CONFIG |
| audit_log_file | /mysql/logs/audit.log | MYSQL_CONFIG |
| audit_log_flush | OFF | MYSQL_CONFIG |
| audit_log_format | JSON | MYSQL_CONFIG |
| audit_log_include_accounts | app_user@192.168.1.% | MYSQL_CONFIG |
| audit_log_include_databases | | MYSQL_CONFIG |
| audit_log_include_events | | MYSQL_CONFIG |
| audit_log_policy | ALL | MYSQL_CONFIG |
| audit_log_rotate_on_size | 104857600 | MYSQL_CONFIG |
| audit_log_rotations | 10 | MYSQL_CONFIG |
| audit_log_strategy | ASYNCHRONOUS | MYSQL_CONFIG |
+—————————–+——————————–+——————-+

# 2. 查看审计日志
# 查看审计日志内容
$ tail -n 10 /mysql/logs/audit.log

# 输出示例
{“timestamp”:”2026-04-10T00:00:00Z”,”id”:123,”class”:”connection”,”event”:”connect”,”connection_id”:123,”status”:0,”user”:”app_user”,”priv_user”:”app_user”,”os_user”:””,”ip”:”192.168.1.100″,”db”:””}
{“timestamp”:”2026-04-10T00:00:01Z”,”id”:124,”class”:”general”,”event”:”query”,”connection_id”:123,”status”:0,”sqltext”:”SELECT
* FROM fgedudb.fgedu_users WHERE id =
1″,”user”:”app_user”,”priv_user”:”app_user”,”os_user”:””,”ip”:”192.168.1.100″,”db”:”fgedudb”}
{“timestamp”:”2026-04-10T00:00:02Z”,”id”:125,”class”:”connection”,”event”:”disconnect”,”connection_id”:123,”status”:0,”user”:”app_user”,”priv_user”:”app_user”,”os_user”:””,”ip”:”192.168.1.100″,”db”:”fgedudb”}

# 3. 审计日志分析
# 使用脚本分析审计日志
#!/bin/bash
# analyze_audit_log.sh

AUDIT_LOG_FILE=”/mysql/logs/audit.log”

# 统计登录失败次数
echo “登录失败次数:”
grep -c “‘event’:’connect’.*’status’:1045” $AUDIT_LOG_FILE

# 统计敏感表修改操作
echo “敏感表修改操作次数:”
grep -c “‘event’:’query’.*’sqltext’:’UPDATE sensitive_table'” $AUDIT_LOG_FILE

# 统计权限变更操作
echo “权限变更操作次数:”
grep -c “‘event’:’query’.*’sqltext’:’GRANT\|REVOKE'” $AUDIT_LOG_FILE

# 执行分析脚本
$ bash /mysql/scripts/analyze_audit_log.sh
登录失败次数:10
敏感表修改操作次数:20
权限变更操作次数:5

# 4. 审计日志清理
# 创建清理脚本
#!/bin/bash
# clean_audit_logs.sh

AUDIT_LOG_DIR=”/mysql/logs”
RETENTION_DAYS=30

# 清理过期的审计日志
find $AUDIT_LOG_DIR -name “audit.log.*” -mtime +$RETENTION_DAYS -type f -exec rm -f {} \;

# 使用crontab定期执行
# crontab -e
# 每天凌晨1点清理审计日志
0 1 * * * /mysql/scripts/clean_audit_logs.sh

# 查看清理日志
# tail -n 10 /mysql/logs/clean_audit.log
2026-04-10 01:00:00 Cleaned 5 old audit log files
2026-04-11 01:00:00 Cleaned 3 old audit log files
2026-04-12 01:00:00 Cleaned 2 old audit log files

# 5. 审计日志安全
# 设置审计日志权限
$ chmod 600 /mysql/logs/audit.log
$ chown mysql:mysql /mysql/logs/audit.log

# 加密审计日志(可选)
# 使用OpenSSL加密审计日志
$ openssl enc -aes-256-cbc -salt -in /mysql/logs/audit.log -out /mysql/logs/audit.log.enc -k encryption_key

# 解密审计日志
$ openssl enc -d -aes-256-cbc -in /mysql/logs/audit.log.enc -out /mysql/logs/audit.log.dec -k encryption_key

3.5 访问控制

MySQL访问控制是限制用户对数据库访问的重要措施,包括以下几个方面:

# 1. 网络访问控制
# 限制用户IP访问
mysql> CREATE USER ‘app_user’@’192.168.1.100’ IDENTIFIED BY ‘secure_password’;
Query OK, 0 rows affected (0.01 sec)

# 允许用户从特定网段访问
mysql> CREATE USER ‘app_user’@’192.168.1.%’ IDENTIFIED BY ‘secure_password’;
Query OK, 0 rows affected (0.01 sec)

# 允许用户从任何IP访问(不推荐)
mysql> CREATE USER ‘app_user’@’%’ IDENTIFIED BY ‘secure_password’;
Query OK, 0 rows affected (0.01 sec)

# 2. 防火墙配置
# 使用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
$ service iptables save

# 使用firewalld限制访问
$ firewall-cmd –permanent –add-source=192.168.1.0/24 –add-port=3306/tcp
$ firewall-cmd –reload

# 3. 资源访问控制
# 限制用户连接数
mysql> CREATE USER ‘app_user’@’192.168.1.%’ IDENTIFIED BY ‘secure_password’ WITH MAX_USER_CONNECTIONS 10;
Query OK, 0 rows affected (0.01 sec)

# 限制用户每小时查询数
mysql> CREATE USER ‘app_user’@’192.168.1.%’ IDENTIFIED BY ‘secure_password’ WITH MAX_QUERIES_PER_HOUR 1000;
Query OK, 0 rows affected (0.01 sec)

# 限制用户每小时更新数
mysql> CREATE USER ‘app_user’@’192.168.1.%’ IDENTIFIED BY ‘secure_password’ WITH MAX_UPDATES_PER_HOUR 500;
Query OK, 0 rows affected (0.01 sec)

# 限制用户每小时连接数
mysql> CREATE USER ‘app_user’@’192.168.1.%’ IDENTIFIED BY ‘secure_password’ WITH MAX_CONNECTIONS_PER_HOUR
100;
Query OK, 0 rows affected (0.01 sec)

# 4. 连接超时控制
# 设置连接超时时间
$ vi /etc/my.cnf
[mysqld]
wait_timeout = 300
interactive_timeout = 300

# 重启MySQL服务
$ systemctl restart mysqld

# 查看连接超时配置
mysql> SHOW VARIABLES LIKE ‘%timeout%’;
+———————————–+———-+——————-+
| Variable_name | Value | Variable_source |
+———————————–+———-+——————-+
| connect_timeout | 10 | MYSQL_CONFIG |
| delayed_insert_timeout | 300 | MYSQL_CONFIG |
| have_statement_timeout | YES | COMPILED |
| innodb_flush_log_at_timeout | 1 | MYSQL_CONFIG |
| innodb_lock_wait_timeout | 50 | MYSQL_CONFIG |
| innodb_rollback_on_timeout | OFF | MYSQL_CONFIG |
| interactive_timeout | 300 | MYSQL_CONFIG |
| lock_wait_timeout | 31536000 | MYSQL_CONFIG |
| net_read_timeout | 30 | MYSQL_CONFIG |
| net_write_timeout | 60 | MYSQL_CONFIG |
| rpl_stop_slave_timeout | 31536000 | MYSQL_CONFIG |
| slave_net_timeout | 60 | MYSQL_CONFIG |
| wait_timeout | 300 | MYSQL_CONFIG |
+———————————–+———-+——————-+

# 5. 账户锁定
# 锁定用户
mysql> ALTER USER ‘app_user’@’192.168.1.%’ ACCOUNT LOCK;
Query OK, 0 rows affected (0.01 sec)

# 解锁用户
mysql> ALTER USER ‘app_user’@’192.168.1.%’ ACCOUNT UNLOCK;
Query OK, 0 rows affected (0.01 sec)

# 查看用户锁定状态
mysql> SELECT User, Host, account_locked FROM mysql.user;
+——————+—————+—————-+——————-+
| User | Host | account_locked | Variable_source |
+——————+—————+—————-+——————-+
| root | localhost | N | NULL |
| mysql.infoschema | localhost | Y | NULL |
| mysql.session | localhost | Y | NULL |
| mysql.sys | localhost | Y | NULL |
| app_user | 192.168.1.% | N | NULL |
+——————+—————+—————-+——————-+

# 6. 登录失败锁定
# 安装连接控制插件
mysql> INSTALL PLUGIN CONNECTION_CONTROL SONAME ‘connection_control.so’;
Query OK, 0 rows affected (0.01 sec)

mysql> INSTALL PLUGIN CONNECTION_CONTROL_FAILED_LOGIN_ATTEMPTS SONAME ‘connection_control.so’;
Query OK, 0 rows affected (0.01 sec)

# 配置登录失败锁定
$ vi /etc/my.cnf
[mysqld]
connection_control_min_connection_delay = 60000 # 60秒
connection_control_max_connection_delay = 3600000 # 1小时
connection_control_failed_connections_threshold = 3 # 3次失败尝试

# 重启MySQL服务
$ systemctl restart mysqld

# 查看登录失败锁定配置
mysql> SHOW VARIABLES LIKE ‘connection_control%’;
+————————————————-+—————-+——————-+
| Variable_name | Value | Variable_source |
+————————————————-+—————-+——————-+
| connection_control_failed_connections_threshold | 3 | MYSQL_CONFIG |
| connection_control_max_connection_delay | 3600000 | MYSQL_CONFIG |
| connection_control_min_connection_delay | 60000 | MYSQL_CONFIG |
+————————————————-+—————-+——————-+

3.6 漏洞管理

MySQL漏洞管理是及时发现和修复安全漏洞的重要措施,包括以下几个方面:

# 1. 漏洞扫描
# 使用MySQL内置工具检查漏洞
$ mysqlcheck –version
mysqlcheck Ver 8.4.0 for Linux on x86_64 (MySQL Community Server – GPL)

# 使用第三方工具检查漏洞
$ nmap -sV –script mysql-vuln-cve2012-2122 192.168.1.10

# 输出示例
Starting Nmap 7.92 ( https://nmap.org ) at 2026-04-10 00:00:00 CST
Nmap scan report for 192.168.1.10
Host is up (0.0010s latency).

PORT STATE SERVICE VERSION
3306/tcp open mysql MySQL 8.4.0
| mysql-vuln-cve2012-2122:
| VULNERABLE:
| MySQL Authentication Bypass Vulnerability
| State: NOT VULNERABLE
| IDs: CVE:CVE-2012-2122
| Risk factor: High CVSSv2: 9.0 (HIGH) (AV:N/AC:L/Au:S/C:C/I:C/A:C)
| Description:
| MySQL through 5.5.23, 5.6.x before 5.6.6, and 5.7.x before 5.7.3 allows remote authenticated users to
bypass intended \n| permission restrictions and delete the mysql.user table via a DROP statement followed by
a CREATE statement, aka \n| bug 14619698.
| Disclosure date: 2012-06-09
| References:
| https://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2012-2122
|_ http://bugs.mysql.com/bug.php?id=14619698

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 10.00 seconds

# 2. 版本更新
# 查看当前MySQL版本
mysql> SELECT VERSION();
+———–+
| VERSION() |
+———–+
| 8.4.0 |
+———–+

# 下载最新版本
$ wget https://dev.mysql.com/get/Downloads/MySQL-8.4/mysql-8.4.1-el7-x86_64.tar.gz

# 升级MySQL
# 风哥教程参考MySQL官方文档进行升级

# 3. 补丁管理
# 安装MySQL补丁
$ yum update mysql-community-server -y

# 查看已安装的补丁
$ yum list installed | grep mysql

# 4. 漏洞修复
# 根据漏洞扫描结果修复漏洞
# 例如:修复CVE-2023-21975漏洞
# 升级到MySQL 8.0.32或更高版本

# 5. 安全公告订阅
# 订阅MySQL安全公告
# https://www.oracle.com/security-alerts/

# 6. 安全基线检查
# 使用MySQL安全基线检查工具
# 例如:mysql_secure_installation
$ mysql_secure_installation

# 输出示例
Securing the MySQL server deployment.

Enter password for user root: # 输入root密码

The existing password for the user account root has expired. Please set a new password.

New password: # 输入新密码

Re-enter new password: # 确认新密码

VALIDATE PASSWORD COMPONENT can be used to test passwords
and improve security. It checks the strength of password
and allows the users to set only those passwords which are
secure enough. Would you like to setup VALIDATE PASSWORD component?

Press y|Y for Yes, any other key for No: y # 安装密码验证组件

There are three levels of password validation policy:

LOW Length >= 8
MEDIUM Length >= 8, numeric, mixed case, and special characters
STRONG Length >= 8, numeric, mixed case, special characters and dictionary file

Please enter 0 = LOW, 1 = MEDIUM and 2 = STRONG: 1 # 选择密码策略

Using existing password for root.
Estimated strength of the password: 100
Change the password for root ? ((Press y|Y for Yes, any other key for No) : n # 不修改root密码

… skipping.
By default, a MySQL installation has an anonymous user,
allowing anyone to log into MySQL without having to have
a user account created for them. This is intended only for
testing, and to make the installation go a bit smoother.
You should remove them before moving into a production
environment.

Remove anonymous users? (Press y|Y for Yes, any other key for No) : y # 删除匿名用户
Success.

Normally, root should only be allowed to connect from
‘localhost’. This ensures that someone cannot guess at
the root password from the network.

Disallow root login remotely? (Press y|Y for Yes, any other key for No) : y # 禁止root远程登录
Success.

By default, MySQL comes with a database named ‘test’ that
anyone can access. This is also intended only for testing,
and should be removed before moving into a production
environment.

Remove test database and access to it? (Press y|Y for Yes, any other key for No) : y # 删除test数据库
– Dropping test database…
Success.

– Removing privileges on test database…
Success.

Reloading the privilege tables will ensure that all changes
made so far will take effect immediately.

Reload privilege tables now? (Press y|Y for Yes, any other key for No) : y # 重新加载权限表
Success.

All done!

Part04-生产案例与实战讲解

4.1 MySQL安全加固实战

MySQL安全加固的实战案例。

案例:MySQL服务器安全加固
系统需求:
– 对MySQL服务器进行全面安全加固,提高系统安全性
– 遵循等保2.0安全要求
– 确保业务的连续性和可用性

# 1. 系统环境准备
# 关闭不必要的服务
$ systemctl disable httpd
$ systemctl disable sshd

# 配置防火墙
$ firewall-cmd –permanent –add-source=192.168.1.0/24 –add-port=3306/tcp
$ firewall-cmd –reload

# 安装安全补丁
$ yum update -y

# 2. MySQL安全加固
# 运行mysql_secure_installation脚本
$ mysql_secure_installation

# 禁用远程root登录
mysql> DELETE FROM mysql.user WHERE User=’root’ AND Host!=’localhost’;
mysql> FLUSH PRIVILEGES;

# 删除匿名用户
mysql> DELETE FROM mysql.user WHERE User=”;
mysql> FLUSH PRIVILEGES;

# 删除test数据库
mysql> DROP DATABASE IF EXISTS test;
mysql> DELETE FROM mysql.db WHERE Db=’test’ OR Db=’test\_%’;
mysql> FLUSH PRIVILEGES;

# 限制root用户权限
mysql> REVOKE ALL PRIVILEGES ON *.* FROM ‘root’@’localhost’;
mysql> GRANT ALL PRIVILEGES ON *.* TO ‘root’@’localhost’ WITH GRANT OPTION;
mysql> FLUSH PRIVILEGES;

# 3. MySQL配置加固
# 修改配置文件
$ vi /etc/my.cnf
[mysqld]
# 基础安全配置
skip_name_resolve = ON
skip_networking = OFF
default_authentication_plugin = caching_sha2_password

# 连接安全配置
max_connections = 1000
wait_timeout = 300
interactive_timeout = 300
connection_control_failed_connections_threshold = 3
connection_control_min_connection_delay = 60000

# 密码安全配置
validate_password.policy = MEDIUM
validate_password.length = 12
validate_password.mixed_case_count = 2
validate_password.number_count = 2
validate_password.special_char_count = 2

# 审计配置
audit_log_format = JSON
audit_log_file = /mysql/logs/audit.log
audit_log_policy = ALL

# 加密配置
ssl-ca = /mysql/ssl/ca.pem
ssl-cert = /mysql/ssl/server-cert.pem
ssl-key = /mysql/ssl/server-key.pem
require_secure_transport = ON

innodb_encrypt_tables = ON
innodb_encrypt_log = ON
innodb_encrypt_temporary_tables = ON

# 4. 文件权限加固
# 设置MySQL数据目录权限
$ chown -R mysql:mysql /mysql/data
$ chmod -R 700 /mysql/data

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

# 设置MySQL日志文件权限
$ chown -R mysql:mysql /mysql/logs
$ chmod -R 600 /mysql/logs

# 设置MySQL SSL证书权限
$ chown -R mysql:mysql /mysql/ssl
$ chmod -R 600 /mysql/ssl

# 5. 重启MySQL服务
$ systemctl restart mysqld

# 6. 验证安全加固效果
# 检查匿名用户是否存在
mysql> SELECT User FROM mysql.user WHERE User=”;
Empty set (0.00 sec)

# 检查root用户远程登录权限
mysql> SELECT User, Host FROM mysql.user WHERE User=’root’;
+——+———–+——————-+
| User | Host | Variable_source |
+——+———–+——————-+
| root | localhost | NULL |
+——+———–+——————-+

# 检查test数据库是否存在
mysql> SHOW DATABASES LIKE ‘test’;
Empty set (0.00 sec)

# 检查SSL配置
mysql> SHOW VARIABLES LIKE ‘require_secure_transport’;
+————————–+——-+——————-+
| Variable_name | Value | Variable_source |
+————————–+——-+——————-+
| require_secure_transport | ON | MYSQL_CONFIG |
+————————–+——-+——————-+

# 检查审计日志配置
mysql> SHOW VARIABLES LIKE ‘audit_log_policy’;
+—————–

本文由风哥教程整理发布,仅用于学习测试使用,转载注明出处:http://www.fgedu.net.cn/10327.html

联系我们

在线咨询:点击这里给我发消息

微信号:itpux-com

工作日:9:30-18:30,节假日休息