数据库安全与运维管控(二):从“共享账号”到本地账密泄露分析
在日常的研发联调和生产排障中开发人员不可避免地需要连接数据库来核对数据或验证逻辑。目前绝大多数企业的做法依然是DBA 在底层数据库中执行GRANT命令创建一个只读账号如dev_readonly然后将 IP 地址和账号密码通过通讯软件发给研发负责人。研发人员拿到账密后配置在 Navicat、DBeaver 或 DataGrip 等本地 C/S 客户端中进行连接。这种延续了十几年的传统直连模式在现代企业的团队协作中正逐渐暴露出严重的安全漏洞与运维死角。本文将从底层账号管理的角度剖析这种模式带来的三大工程隐患。一、 追责断层“共享高级账号”带来的黑盒化为了减少建号的工作量DBA 通常倾向于按环境或按项目组建立共享账号。例如为整个订单组的 20 个开发人员分配同一个order_ro账号。这种做法在系统正常运行时没有问题但一旦发生生产事故就会引发严重的“追责断层”。身份无法穿透结合上一篇文章提到的原生审计日志当数据库发生 CPU 飙高因为一条烂 SQL或敏感数据被违规导出时DBA 去查底层审计日志看到的user字段永远是order_ro。IP 溯源的局限性有人认为可以通过审计日志中的host源 IP来反查物理责任人。但在实际办公网络中开发人员通常使用动态 DHCP 分配的内网 IP甚至通过 VPN、跳板机连入。一个月后去追溯某个内网 IP 当时分给了谁在绝大多数公司是不现实的。底层数据库只认“账密”不认“自然人”。这种物理连接身份与实际操作人身份的剥离让企业的数据合规审查形同虚设。二、 物理账密下发导致的权限失控与泄露只要物理密码离开了 DBA 的剪贴板分发到了客户端其生命周期就彻底失控了。1. 客户端软件的本地缓存风险Navicat、DBeaver 等客户端工具为了方便用户会将数据库连接串和密码加密或明文/弱加密保存在本地配置文件中。这类工具通常还带有“导出连接配置”功能。 这意味着任何一个拿到账密的实习生或外包人员都可以轻易将包含生产库密码的配置文件导出发给外部人员或者带离办公场所。2. 密码轮转Rotation的工程灾难安全规范通常要求生产环境密码每 90 天轮转一次。对于应用服务器连接的密码可以通过修改 Apollo/Nacos 配置中心平滑生效。 但对于下发给研发人员的个人查询账号密码轮转是一场灾难DBA 执行ALTER USER dev_ro IDENTIFIED BY new_password;后所有正在使用该账号的研发人员的本地客户端瞬间报错。DBA 必须再次通过邮件或群聊同步新密码研发人员需要逐个修改本地配置。如果某些开发人员手写了本地 Python 脚本做数据拉取密码写死在代码里轮转会直接导致脚本报错。因为轮转成本太高很多公司的查询账号密码几年都不换甚至人员离职半年后其本地电脑上的 Navicat 依然能直连生产库。三、 原生 GRANT 权限控制的粗放与僵化除了账密泄露通过数据库底层原生命令分配权限其粒度也极难把控。1. 难以实现细粒度的库表隔离假设一个 MySQL 实例里有 50 个逻辑库Schema开发人员申请访问其中 2 个库的只读权限。 DBA 需要写极其繁琐的授权语句GRANT SELECT ON db1.* TO user_a%; GRANT SELECT ON db2.* TO user_a%;如果需求变成“只能看 db1 的orders表且不能看表里的phone字段”DBA 只能建立视图View然后再把视图的权限授权给该用户。这在频繁迭代的业务中维护成本高得令人发指。2. 缺乏时间维度的权限熔断很多时候开发人员只是为了排查某个线上 Bug临时需要 2 个小时的生产库查询权限。 底层数据库不支持GRANT SELECT ... EXPIRE IN 2 HOURS这样的语法。DBA 给完权限后如果没有健全的工单系统做回收提醒这个临时权限往往会变成永久权限。久而久之生产库上堆积了大量不知归属、权限过大的僵尸账号。四、 总结总结来看只要企业还在允许研发人员使用 C/S 客户端工具物理账密直连核心数据库以上三大隐患就从原理上无法根除。用共享账号没法实名追责。发物理密码没法防泄露和低成本轮转。用底层 GRANT没法做到细粒度和临时性的权限管控。要解决这些运维层面的顽疾思路不能局限在数据库引擎内部而是要在网络层与应用层做文章必须收缴所有客户端的直连权限建立一道挡在物理数据库前面的代理层Proxy或网关。