数据库权限管理最怕的就是“一刀切”和“一放了之”。很多团队为了开发效率,直接给root或者sysadmin权限,时间一长,谁有权限、权限用来干什么,完全是一笔糊涂账。定期审计不是去翻那些枯燥的日志,而是要建立起一套能落地、能自动化的实操体系。下面直接讲具体的执行步骤和优化方法。
建立动态的最小权限基线最小权限原则大家都会说,但难在执行。你不能今天把权限收紧了,明天业务就跑不通。实操的第一步,不是直接改权限,而是先建立基线。拿出一个脚本,把当前所有账户的权限全部导出来。对于MySQL,可以直接查询mysql.user和information_schema中的权限表;对于PostgreSQL,查询pg_roles和information_schema.role_table_grants。把这些权限清单和业务负责人逐一确认,标记出哪些是实际需要的,哪些是历史遗留的。这个过程会暴露大量问题,比如离职员工的账号还在、测试账号拥有生产库的写权限。确认完成后,形成一份《权限-角色-业务》映射表,这就是后续所有审计的基准线。没有这个基线,审计就是走过场。
审计核心:识别异常权限与幽灵账号有了基线,审计脚本就能派上用场。审计不是简单地看谁登录了,而是要找“异常”。第一个重点,查幽灵账号。写一条SQL,找出那些超过30天没有登录过的数据库账户。这类账户往往是安全重灾区,要么是离职人员未清理,要么是临时项目结束后遗忘。第二个重点,查权限漂移。对比当前权限快照和基线,找出新增的、提权的账户。尤其是那些突然被授予了SUPER、FILE、ALTER等高危权限的普通账户,必须立刻报警。第三个重点,查弱密码和空口令。虽然运维层面会做密码强度校验,但数据库内部账户,比如复制账号、监控账号,常常被设置为弱密码。定期执行密码复杂度检查脚本,或者直接对接企业的统一认证系统,是根治之道。
高危权限的精细化治理有些权限天生就带着高风险属性,不能简单地给或者不给,要做精细化拆分。以MySQL为例,SUPER权限能改只读参数、杀连接、改复制状态,太大了。实操中,应该用更细粒度的权限替代。比如,只需要杀连接,就只给PROCESS权限;只需要做备份,就给SELECT和LOCK TABLES,而不是RELOAD。对于FILE权限,它能让数据库读写服务器文件系统,绝大多数应用场景根本不需要,应该全局禁用,除非是特定的ETL机器。还有DML和DDL权限必须分离。开发人员日常操作只给DML(SELECT, INSERT, UPDATE, DELETE),DDL(CREATE, ALTER, DROP)权限必须走审批流程,由专门的变更平台代理执行。这样即使账号泄露,攻击者也改不了表结构,删不了库。
审计日志的开启与自动化分析数据库自带的审计日志是发现问题的眼睛,但很多DBA不敢开,怕影响性能。现在主流数据库的审计插件性能损耗已经控制得很低,比如MySQL Enterprise Audit或者Percona的审计插件,只要不是全量记录SELECT,只记录DDL、DCL和高风险DML,对性能的影响基本可以忽略。关键是要配置好过滤规则。日志收集上来后,不要堆在那里,要接入自动化分析管道。用简单的脚本或者ELK体系,监控几个关键指标:单IP的登录失败次数、非业务时间的大批量数据导出操作、以及grant语句的执行。一旦发现grant操作,必须能实时推送告警,并附带完整的SQL文本和执行人信息。这比事后翻日志有效得多。
权限变更流程的硬约束审计发现的问题,根源都在变更流程上。如果权限变更还是靠DBA手动敲命令,那合规性永远好不了。必须把权限变更线上化、工单化。工单里要强制填写申请理由、涉及的业务库表、使用期限。这里有一个容易被忽视的实操细节:权限有效期。临时权限一定要设置过期时间,到期自动回收。MySQL从8.0版本开始支持角色和部分权限的过期设置,PostgreSQL也有类似功能。对于不支持自动过期的版本,可以在工单系统里设置定时任务,到期后调用预置的回收脚本。这样就避免了“临时提权变永久后门”的问题。所有工单和操作记录都要关联起来,形成从申请到回收的完整闭环。
利用数据库角色重构权限体系如果权限管理还是直接往用户上挂,那规模一大就失控了。重构权限体系的实操方法,是建立角色层级。先梳理业务场景,定义出只读角色、读写角色、备份角色、管理角色等。然后把这些角色授予用户,而不是直接给用户挂权限。这样做的好处是,当业务调整时,只需要修改角色的权限,所有继承该角色的用户自动生效。对于不同环境(开发、测试、生产),要使用不同的角色实例,但命名规则保持一致。在PostgreSQL中,角色继承机制很完善;在MySQL 8.0中,role功能也足够好用。重构过程中,可以写一个存储过程,批量把现有用户的权限转换为角色授权,这样能极大减少人工迁移的工作量和出错概率。
敏感数据的列级权限控制表级的SELECT权限还是太粗了。对于手机号、身份证、资金余额这类敏感字段,必须做到列级权限控制。大部分数据库都支持列级授权,但实际用得很少,因为管理复杂。实操中,可以结合视图来简化。创建一个不包含敏感列的视图,把视图的查询权限给普通开发人员。对于确实需要访问完整数据的场景,再通过存储过程封装,存储过程内部做脱敏或者记录访问日志。这样既满足了查询需求,又避免了数据泄露。动态数据脱敏插件也是不错的选择,可以在数据库返回结果集时自动对敏感字段打码,但需要评估插件对查询性能的影响,通常建议在从库或分析库上使用。
审计脚本的实战示例下面给一个MySQL的审计脚本片段,用来找出没有设置密码或者密码为空的账户,以及拥有全局高危权限的非root账户。这类脚本可以放在定时任务里,每周跑一次。
-- 检查空口令用户(MySQL 5.7版本)
SELECT user, host
FROM mysql.user
WHERE authentication_string = ''
OR authentication_string IS NULL;
-- 检查拥有SUPER或FILE权限的非管理账户
SELECT GRANTEE, PRIVILEGE_TYPE
FROM information_schema.user_privileges
WHERE PRIVILEGE_TYPE IN ('SUPER', 'FILE', 'SHUTDOWN')
AND GRANTEE NOT LIKE '%root%'
AND GRANTEE NOT LIKE '%repl%';
对于PostgreSQL,可以这样检查超级用户权限的账户:
-- 检查具有SUPERUSER属性的非postgres角色
SELECT rolname
FROM pg_roles
WHERE rolsuper = true
AND rolname NOT IN ('postgres', 'replication_user');
这些脚本输出结果后,需要人工二次确认,然后纳入整改清单。关键是坚持执行,不能跑一次发现一堆问题,然后就不了了之。
权限审计与安全优化的常态化安全优化不是一次性的项目,而是一个持续运转的机制。把权限基线维护、幽灵账号清理、高危权限监控、日志分析这些动作,拆解成每周或每月的固定任务,分配给具体的责任人。在季度大审计时,再做一次全面的权限梳理和角色重构评估。当业务系统上云或采用容器化部署后,数据库权限管理还要和云厂商的RAM策略、Kubernetes的Secret管理联动,确保从基础设施到应用层,每一层都遵循最小权限原则。只有把审计变成日常操作,数据库的安全水位才能真正提升,而不是靠突击检查来应付合规。
