数据库密码安全配置与权限分级管理,本质上是在解决一个核心矛盾:既要让应用程序和运维人员能正常访问数据,又要防止密码泄露后攻击者长驱直入。很多数据库被拖库的案例里,问题往往不是加密算法不够强,而是密码策略形同虚设、所有账号都拿着最高权限、一条连接串走天下。真正有效的防护,是把密码当成会过期的凭证,把权限当成按需分配的资源,而不是一次性配置完就再也不管。

密码安全配置的第一步:强制基础策略

数据库安装完成后,第一件要做的事就是修改默认账号和默认端口。MySQL 的 root、SQL Server 的 sa、PostgreSQL 的 postgres,这些超级账号名本身就是攻击者暴力破解的首选目标。如果业务允许,直接禁用远程登录这些超级账号,或者将其重命名为无规律的名称。同时,必须开启密码复杂度校验。以 MySQL 8.0 为例,可以通过 validate_password 组件强制密码长度、混合大小写、数字和特殊字符。单纯依赖前端应用做复杂度校验没有意义,因为攻击者可能通过其他入口直连数据库。

密码过期策略同样重要。很多企业的数据库密码从上线到退役都没换过,内部员工离职后依然掌握着连接信息。合理的做法是设置密码生命周期,例如 90 天强制更换,并保留密码历史记录防止重复使用旧密码。对于高权限账号,还可以启用双因素认证或至少要求运维人员通过堡垒机跳转,避免密码直接暴露在个人终端上。

密码存储与传输:杜绝明文落地

应用程序连接数据库时,连接串里的密码绝对不能明文写在配置文件或代码仓库中。常见的错误做法是把密码硬编码在 application.properties、web.config 或环境变量里,然后连同源码一起提交到 Git。一旦代码仓库泄露,数据库密码就跟着泄露。正确的做法是使用密钥管理服务或专用的凭据存储,例如 HashiCorp Vault、云厂商的 Secrets Manager,让应用在运行时动态获取密码。如果条件有限,至少也要对配置文件中的密码做对称加密,并把解密密钥放在操作系统级别的权限保护下。

传输层面,数据库客户端与服务端之间的通信必须启用 TLS/SSL 加密。很多内网环境认为内部网络是安全的,就关闭了加密传输,但实际上内网横向渗透是攻击者常用的手段。开启 TLS 后,即使有人在网络层抓包,也无法直接还原出明文密码。对于 MySQL,可以配置 require_secure_transport=ON 强制所有连接走加密通道;PostgreSQL 则可以在 pg_hba.conf 中指定 hostssl 规则。

权限分级管理的核心原则:最小权限

权限分级不是简单地把账号分成管理员和普通用户两类,而是要根据实际业务场景,把访问权限细化到库、表、甚至列级别。一个只负责读取订单报表的服务,不应该拥有对用户表的写权限;一个只操作某个业务库的应用账号,不应该能看到系统库或其它业务库的数据。最小权限原则意味着每个账号只拥有完成当前任务所必需的最小权限集合,并且这个集合要定期审查和回收。

实施最小权限时,先梳理业务数据流。哪些应用需要读写哪些表?哪些报表任务只需要只读权限?哪些运维操作需要 DDL 权限?把这些需求列成清单,然后为每个应用或服务创建独立的数据库账号,而不是让多个应用共用一个账号。共用一个账号的后果是,一旦某个应用被 SQL 注入攻破,攻击者拿到的连接权限可以横向访问所有业务数据。

角色与权限组的设计

在数据库层面,可以通过角色来简化权限管理。以 PostgreSQL 为例,可以创建 read_only、read_write、app_admin 等角色,把对应的表级权限授予角色,再把角色授予具体的登录账号。这样当业务调整需要批量修改权限时,只需要改角色定义,而不必逐个修改账号。MySQL 8.0 也支持角色功能,但很多从 5.7 迁移过来的系统还停留在直接给账号授权的老习惯上,这会让权限管理越来越混乱。

角色设计要遵循职责分离的原则。开发人员日常使用的账号不应拥有生产库的 DDL 权限;数据分析师只需要只读权限,并且最好通过只读副本访问,避免影响主库性能;应用账号只拥有业务库的增删改查权限,禁止访问 mysql.user、pg_authid 这类系统权限表。对于需要执行备份、恢复、主从切换等运维操作的账号,可以单独设置一个高权限角色,但必须限制其来源 IP,并开启操作审计。

细粒度权限控制实例

以 MySQL 为例,假设有一个订单服务应用,它只需要访问 orders 数据库中的 orders 表和 order_items 表。创建账号时不应该使用 GRANT ALL PRIVILEGES,而是精确指定:

CREATE USER 'order_svc'@'10.0.1.%' IDENTIFIED BY '强密码';
GRANT SELECT, INSERT, UPDATE, DELETE ON orders.orders TO 'order_svc'@'10.0.1.%';
GRANT SELECT, INSERT, UPDATE, DELETE ON orders.order_items TO 'order_svc'@'10.0.1.%';
FLUSH PRIVILEGES;

这里还限制了来源 IP 段,意味着即使密码泄露,攻击者从其它网段也无法连接。对于只需要读取用户表邮箱字段的报表任务,可以进一步做列级授权:

GRANT SELECT (user_id, email) ON users.users TO 'report_ro'@'10.0.2.%';

列级权限能有效防止敏感字段被不必要地读取。类似地,PostgreSQL 支持行级安全策略,可以在表上创建策略,让不同角色只能看到符合特定条件的行。例如,区域经理只能看到自己负责区域的数据,而不是整张销售表。

超级账号的管控与降权

超级账号是权限分级管理中最危险的存在。很多企业为了方便,开发、测试、运维人员都直接使用 root 或 sa 账号操作数据库。一旦某个终端被植入木马,或者某个人误操作,整个数据库都可能被清空。正确的做法是:生产环境的超级账号只允许通过堡垒机登录,并且开启操作审计;日常 DDL 操作通过专门的 DDL 账号执行,该账号只拥有结构变更权限,没有数据读写权限;紧急情况下的超级权限采用临时授权机制,例如通过工单申请,审批通过后授予限时的高权限角色,时间一到自动回收。

MySQL 中可以通过设置 sql_log_bin 和开启 general_log 来记录超级账号的操作,但更推荐使用审计插件。PostgreSQL 可以使用 pgaudit 扩展记录所有敏感操作。审计日志要独立存储,避免攻击者拿到数据库权限后同时删除日志。

密码轮换与自动化管理

密码轮换不能靠人工记忆和手动修改。当数据库实例数量多、账号多的时候,人工轮换必然会出现遗漏和配置不同步。自动化轮换的思路是:应用不再硬编码密码,而是通过凭据管理服务获取。轮换时,凭据管理服务先调用数据库接口修改密码,然后更新存储的凭据版本,应用下一次获取时自动拿到新密码。对于无法改造的老旧应用,可以采用双密码过渡策略,即在数据库中临时允许新旧两个密码同时有效,待所有连接都切换到新密码后再删除旧密码。

轮换周期要根据账号级别区分。超级账号和具有写权限的业务账号建议 30 到 60 天轮换一次;只读账号可以适当放宽到 90 天;临时授权的账号则应在任务结束后立即删除或禁用。每次轮换后要验证旧密码确实失效,避免出现配置未生效的情况。

监控与异常检测

密码策略和权限分级配置得再好,也需要监控来兜底。重点关注几类异常:同一账号在短时间内从多个不同 IP 登录;账号在非工作时间频繁尝试连接;连续多次密码错误后突然成功;高权限账号从非堡垒机 IP 登录。这些行为往往意味着密码泄露或暴力破解正在进行。数据库自带的日志可以提供基础信息,但更有效的方式是接入集中式日志分析平台,设置告警规则。

对于权限变更,也要建立审批和通知机制。任何对用户权限的 GRANT、REVOKE、CREATE USER、DROP USER 操作都应该被记录并通知安全管理员。很多权限失控的案例,都是因为某个开发人员为了方便临时给自己加了权限,事后忘记回收,最终成为安全隐患。

常见误区与加固建议

一个常见的误区是认为内网数据库不需要复杂的密码策略。事实上,内网渗透中数据库往往是攻击者的首要目标,因为数据价值最高。另一个误区是过度依赖网络隔离,认为只要数据库不暴露公网就安全了。网络隔离只能挡住外部攻击者,挡不住内部恶意人员或已经被攻破的内网主机。所以密码策略和权限分级必须同时落实,不能偏废。

此外,测试环境和生产环境要严格隔离权限。测试库的密码不要和生产库相同或相似,测试账号不要拥有生产库的任何权限。很多数据泄露事件是因为测试环境被攻破后,攻击者利用相同的密码或配置横向登录了生产环境。

最后,定期进行权限审计和密码策略检查。可以编写脚本定期导出数据库用户列表、权限矩阵和密码最后修改时间,与业务需求清单比对,发现多余权限或过期账号立即处理。权限管理不是一次性工程,而是一个持续收敛的过程。