加固MySQL服务器安全配置的最佳实践

通过最小权限用户、主机限制、TLS、更安全的my.cnf设置、补丁更新和基本审计来加固MySQL。

加固MySQL服务器安全配置的最佳实践

MySQL加固从一个简单的问题开始:如果一个应用程序密码泄露,攻击者能获得什么?如果答案是“从任何地方访问所有数据库”,那么你的服务器需要更严格的用户、网络规则和配置。

使用这些实践来减少被攻破的影响范围,同时不使日常管理变得繁琐。

1. 用户和访问管理:最小权限原则

有效的用户管理是MySQL安全的基础。只授予用户绝对必要的权限至关重要。

为特定应用程序创建特定用户

避免使用root用户进行应用程序连接。相反,创建具有细粒度权限的专用用户。

CREATE USER 'my_app_user'@'localhost' IDENTIFIED BY 'StrongPassword123!';
GRANT SELECT, INSERT, UPDATE, DELETE ON `your_database`.* TO 'my_app_user'@'localhost';

强制使用强密码

强且唯一的密码是你的第一道防线。如果可用,利用MySQL内置的密码验证插件。

  • 复杂性:混合大小写字母、数字和符号。
  • 长度:至少12-16个字符。
  • 唯一性:绝不重复使用密码。
  • 轮换:实施定期更改密码的策略。

你可以启用validate_password组件(MySQL 8.0+)或插件(MySQL 5.7+):

INSTALL COMPONENT 'file://component_validate_password';
-- 或者对于旧版本
INSTALL PLUGIN validate_password SONAME 'validate_password.so';

-- 配置强度策略(例如,MEDIUM表示8个以上字符,混合大小写,数字,特殊字符)
SET GLOBAL validate_password.policy = MEDIUM;
SET GLOBAL validate_password.length = 12;

移除默认和未使用的用户

MySQL可能包含管理性和内部账户。保留必需的系统账户,如mysql.sessionmysql.sys,但移除匿名账户以及任何不再使用的人为或应用程序账户。

-- 识别匿名用户:
SELECT user, host FROM mysql.user WHERE user = '';
-- 删除匿名用户(如果找到):
DROP USER ''@'localhost';

-- 移除测试数据库(如果存在):
DROP DATABASE IF EXISTS test;
DELETE FROM mysql.db WHERE Db='test' OR Db='test\_%';
FLUSH PRIVILEGES;

限制主机访问

限制用户账户只能从特定的IP地址或主机名连接。除非绝对必要并配合其他强安全控制,否则避免使用%作为主机通配符。

-- 用户只能从本地主机连接
CREATE USER 'admin'@'localhost' IDENTIFIED BY 'AnotherStrongPass!';

-- 用户只能从特定IP地址连接
CREATE USER 'backup_user'@'192.168.1.100' IDENTIFIED BY 'BackupPass!';

谨慎使用GRANT OPTION

WITH GRANT OPTION子句允许用户将自己的权限授予其他用户。如果授予不受信任的用户,这可能是一个重大的安全风险。请谨慎使用,仅用于真正需要此能力的管理账户。

-- 具有授予权限能力的用户(极其谨慎使用)
CREATE USER 'superadmin'@'localhost' IDENTIFIED BY 'SuperAdminPass!';
GRANT ALL PRIVILEGES ON *.* TO 'superadmin'@'localhost' WITH GRANT OPTION;

2. 网络安全:隔离你的数据库

网络层面的控制对于防止未经授权的外部访问你的MySQL服务器至关重要。

配置防火墙

仅允许来自受信任IP地址或网络的连接访问MySQL的默认端口(3306)。阻止所有其他到此端口的入站连接。

示例(Linux上的UFW):

sudo ufw enable
sudo ufw allow from 192.168.1.0/24 to any port 3306
sudo ufw deny 3306
sudo ufw status

示例(CentOS/RHEL使用firewalld):

sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.0/24" port port="3306" protocol="tcp" accept'
sudo firewall-cmd --permanent --remove-port=3306/tcp --zone=public # 确保它没有全局开放
sudo firewall-cmd --reload

使用SSL/TLS保护连接

使用SSL/TLS加密客户端和MySQL服务器之间的所有流量,以防止窃听和中间人攻击。这对于通过不受信任网络的连接尤其重要。

要启用SSL/TLS,通常需要生成SSL证书和密钥,然后配置你的my.cnf

# my.cnf
[mysqld]
ssl_ca=/etc/mysql/certs/ca.pem
ssl_cert=/etc/mysql/certs/server-cert.pem
ssl_key=/etc/mysql/certs/server-key.pem

然后客户端应配置为使用SSL/TLS连接,通常在用户的GRANT语句中使用REQUIRE SSL

CREATE USER 'ssl_user'@'%' IDENTIFIED BY 'SSLUserPass!';
GRANT SELECT ON `your_database`.* TO 'ssl_user'@'%' REQUIRE SSL;

绑定到特定IP地址

默认情况下,MySQL可能会监听所有可用的网络接口(0.0.0.0)。将其限制为仅监听需要接受连接的接口(例如,本地应用程序的localhost,或内部连接的私有网络IP)。

# my.cnf
[mysqld]
bind-address = 127.0.0.1  # 仅用于本地连接
# 或者
bind-address = 192.168.1.10  # 用于特定的内部IP

提示:如果你的应用程序和MySQL服务器在同一台机器上,bind-address = 127.0.0.1(本地主机)是最安全的选择,因为它完全阻止了任何外部连接。

3. 配置文件加固(my.cnf / my.ini

MySQL配置文件(Linux上的my.cnf,Windows上的my.ini)提供了许多参数来增强安全性。

禁用未使用的功能

通过禁用部署中不需要的功能来最小化攻击面。

  • local_infile = 0:禁用LOAD DATA LOCAL INFILE,否则当客户端和服务器都允许时,它可以从客户端主机读取文件。
    [mysqld]
    local_infile = 0
    
  • skip-networking:如果你的数据库仅由同一服务器上的应用程序访问,则完全禁用网络。这强制所有连接使用Unix套接字或命名管道。
    [mysqld]
    skip-networking
    
  • symbolic-links = 0:防止对数据库表空间使用符号链接,这可能会被利用来访问MySQL数据目录之外的文件。
    [mysqld]
    symbolic-links = 0
    
  • secure_file_priv:限制文件导入和导出操作(如LOAD DATA INFILESELECT ... INTO OUTFILE)使用的目录。
    [mysqld]
    secure_file_priv = /var/lib/mysql-files
    

secure_file_priv设置为MySQL服务账户拥有的专用目录。不要指向/tmp、应用程序上传目录或不受信任用户可以写入的路径。

避免在选项文件中使用明文密码

客户端选项文件可能会意外地将数据库密码暴露给任何可以读取它的人。如果必须为自动化存储凭据,请限制文件权限并使用专用的低权限账户。

chmod 600 /home/backup/.my.cnf
chown backup:backup /home/backup/.my.cnf

对于交互式管理,最好提示输入密码:

mysql -u admin -p

4. 补丁和验证服务器

安全配置无法拯救一个未打补丁的服务器。通过正常的软件包或供应商更新流程,保持MySQL、客户端库和操作系统的更新。

更改my.cnf后,在维护窗口期间验证并重启:

mysqld --validate-config
sudo systemctl restart mysql
sudo systemctl status mysql

软件包名称和服务名称因发行版而异。某些系统使用mysqld而不是mysql

5. 监控访问和审查权限

加固在第一次通过后并未完成。定期审查账户和授权,特别是在应用程序更改或人员变动之后。

SELECT user, host, account_locked FROM mysql.user ORDER BY user, host;
SHOW GRANTS FOR 'my_app_user'@'localhost';

注意那些使用%主机、宽泛的*.*权限、FILESUPERSYSTEM_USERWITH GRANT OPTION的账户。这些权限可能对少数管理账户有效,但绝不应出现在常规应用程序用户上。

要点

分层加固MySQL。从专用的最小权限用户开始,限制他们可以连接的位置,在跨网络时加密流量,禁用你不使用的危险功能,并保持服务器打补丁。然后安排权限审查,以便旧访问不会悄然成为你的下一个事件。