在开展安全加固或等级保护相关工作的过程中,我个人倾向于保持一种务实的态度。这并非是对安全本身有任何异议,而是注意到部分安全厂商所提供的整改建议,有时过于注重形式化要求,可能在实际运维中引入“无效”成本,甚至影响系统稳定性。例如,在某些场景下,安全扫描工具本身就可能引发服务异常,这类情况在实际运维中并不少见。
就数据库而言,若其部署于内网环境,并已实施了适当的网络隔离与权限管控,实际风险通常远低于安全评估报告中所描述的严重程度。近期,我们在某客户的MySQL数据库中识别出若干待整改项,借此机会做了简要记录与整理。
像MySQL、redis这种开源数据库,通常仅提供基本功能,本身不直接提供内置的、完善的密码策略管理功能。比如像密码复杂度限制,包含大小写;密码有效期,错误密码深度次数,锁定多久,登录记录、审计操作。 这些功能在Oracle 这种商业化软件较为常见。
密码策略
MySQL 从 5.7 版本开始,引入了一个名为 validate_password 的插件,专门用于检查和强制执行密码策略。
SELECT PLUGIN_NAME, PLUGIN_STATUS FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME LIKE 'validate%';
常见的可配置策略项:
| 变量名 | 含义 | 默认值(可能因版本而异) | 设置示例 |
|---|---|---|---|
validate_password_policy | 密码强度策略等级 | MEDIUM | STRONG |
validate_password_length | 密码最小长度 | 8 | 12 |
validate_password_mixed_case_count | 至少需要的大写+小写字母数 | 1 | 2 |
validate_password_number_count | 至少需要的数字个数 | 1 | 1 |
validate_password_special_char_count | 至少需要的特殊字符个数 | 1 | 1 |
密码有效期
长期使用同一个密码会增加密码被暴力破解或泄露的风险。定期更换密码是纵深防御策略中的重要一环,可以有效降低此类风险。MySQL中可以通过变量全局的配置密码时效,或指定用户限制。但该配置同常于应用程序相匹配,防止密码过期应用无法连接,建议应用手动定期在应用版本时更改密码。
设置全局密码过期策略
您可以为所有用户设置一个全局的密码过期时间。例如,设置所有用户的密码每90天必须更换:
SET GLOBAL default_password_lifetime = 90;
为特定用户设置独立的过期策略
对于某些特定账户(如root),您可能希望设置更短的过期时间。可以使用 ALTER USER 语句。
-- 将用户'root'@'localhost'的密码设置为30天过期 ALTER USER 'root'@'localhost' PASSWORD EXPIRE INTERVAL 30 DAY; -- 让某个用户的密码立即过期,下次登录时必须修改 ALTER USER 'some_user'@'%' PASSWORD EXPIRE;
验证设置
mysql> SHOW VARIABLES LIKE 'default_password_lifetime';
+---------------------------+-------+
| Variable_name | Value |
+---------------------------+-------+
| default_password_lifetime | 0 |
+---------------------------+-------+
1 row in set (0.00 sec)
mysql> select host,user,password_last_changed,password_lifetime,password_expired,account_locked from user;
+-----------+-----------------+-----------------------+-------------------+------------------+----------------+
| host | user | password_last_changed | password_lifetime | password_expired | account_locked |
+-----------+-----------------+-----------------------+-------------------+------------------+----------------+
| localhost | root | 2023-07-29 12:05:56 | NULL | N | N |
| localhost | mysql.session | 2023-07-29 12:05:29 | NULL | N | Y |
登录失败限制
Connection_control插件库允许管理员在连续指定次数的不成功登录尝试后,增加服务器对连接的响应延迟。
SET GLOBAL connection_control_failed_connections_threshold = 3; SET GLOBAL connection_control_min_connection_delay = 1000; SET GLOBAL connection_control_min_connection_delay = 90000;
注意可能会带个《MySQL安全插件connection_control及导致链接耗尽”Waiting in connection_control plugin”》之前写到的可用性风险。
帐号策略
默认的root用户
MySQL安装后默认创建的root账户拥有最高权限,是攻击者的首要目标。如果其密码被破解,整个数据库将完全沦陷。可以强化root登录.为root设置强密码:确保root密码是足够复杂和冗长的。
禁止远程root登录:确保没有名为 'root'@'%' 的用户。root账户应只允许从数据库服务器本机('root'@'localhost')登录。
-- 查看所有root用户 SELECT user, host FROM mysql.user WHERE user = 'root'; -- 删除允许从任何主机登录的root账户(谨慎操作!请先确认) DROP USER 'root'@'%';
权限未分离
所有管理任务都由root账户完成,不符合“三权分立”(通常指系统管理员、安全管理员、审计管理员)的安全原则。一旦一个账号泄露,所有功能权限都会丢失,且无法进行有效的操作审计和追溯。
根据您的业务需求,至少应创建以下三类账户:
系统管理员(sysadmin):负责数据库的日常运维,如创建/删除数据库、表、用户,数据备份/恢复等。
-- 创建管理员用户,限制其登录IP为运维网络段 CREATE USER 'sysadmin'@'192.168.1.%' IDENTIFIED BY 'StrongPassword!123'; -- 授予其广泛的权限,但不包括敏感的管理权限 GRANT RELOAD, PROCESS, CREATE, ALTER, DROP, INSERT, SELECT, UPDATE, DELETE, INDEX, CREATE VIEW, SHOW VIEW, EVENT, TRIGGER ON *.* TO 'sysadmin'@'192.168.1.%'; -- 注意:谨慎授予 FILE, SUPER, GRANT OPTION 等高级权限。
安全管理员(secadmin):负责账户管理和安全策略,如创建/删除用户、授权、设置密码策略等。
-- 创建安全管理员用户,限制其只能从特定管理主机登录 CREATE USER 'secadmin'@'192.168.1.100' IDENTIFIED BY 'AnotherStrongPassword!456'; -- 授予其账户管理权限 GRANT CREATE USER, ALTER USER, DROP USER ON *.* TO 'secadmin'@'192.168.1.100'; -- 注意:为了使其能设置密码,通常也需要 GRANT OPTION 权限,但这权限过大,需谨慎。 -- 更安全的做法是,secadmin通过具有SUPER权限的会话执行ALTER USER,或者由root执行。 -- 授予其在mysql系统数据库上的SELECT权限,以便查看用户信息 GRANT SELECT ON mysql.* TO 'secadmin'@'192.168.1.100';
审计管理员(auditadmin):负责查看日志,监控数据库活动,但不能修改数据。当然mysql并没有审计功能,需要MySQL官方企业版( MySQL Enterprise Audit插件 )或相应的插件(MariaDB Audit Plugin )。
-- 创建审计员用户 CREATE USER 'auditadmin'@'192.168.1.200' IDENTIFIED BY 'AuditPassword!789'; -- 授予其只读权限和日志查看权限 GRANT SELECT ON *.* TO 'auditadmin'@'192.168.1.200'; -- 授予 PROCESS 权限,可以查看所有正在执行的语句(SHOW PROCESSLIST) GRANT PROCESS ON *.* TO 'auditadmin'@'192.168.1.200'; -- 如果使用了MySQL企业版的审计插件,还需要授予相关的审计权限。
为应用程序创建专属账户
永远不要使用上述任何管理账户或root账户来连接应用程序。应为每个应用或服务创建独立的、权限最小的账户。如可以只读用户和读写用户。
定期使用 SHOW GRANTS FOR 'user'@'host'; 命令审查各账户的权限,确保没有权限蔓延。
注:安全配置需要在测试环境验证后,再实施数据库。