在日常的研发联调和生产排障中,开发人员不可避免地需要连接数据库来核对数据或验证逻辑。
目前绝大多数企业的做法依然是: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)或网关。