其他系列文章导航
文章目录
前言
情况:
某天中午,公司的产品出现了问题,有人汇报说所有用户都变成了管理员,并且可以享受管理员的权限。
然后员工小 A 大叫:“我 X,是我今天执行单元测试更新数据的时候,少加了个 where 条件!”
本来的预期:update user set userRole = 'admin' where id = 1 实际上执行:update user set userRole = 'admin'
于是导致整个库里的所有用户都变成了管理员,并且可以享受管理员的权限。
一、处理措施
解释一下,就跟我们在路上看到一起交通事故一样,第一时间要么是保护现场,放一个小牌牌不让大家进到事故发生地;要么就是防止扩大影响,人工疏导不让更多人围观、阻塞交通。
一般这两件事情是同时执行的,由于我知道怎么能够判定哪些用户本来是 VIP(比如通过 VIP 信息)、而且程序又有详细的日志,所以第一时间是让员工先把 user 表的所有角色设置为普通用户权限,防止有人继续利用管理员权限去做一些不好的事情。
接下来就是立刻停止了线上的前后端服务,一方面是为了后面好恢复数据,另外也是防止一些同学发现自己突然从会员变成了普通用户,增加大量的人工咨询成本。
稳定现场后,接下来就是想办法恢复数据到正常的状态,好在我给数据库设置了分钟级别的备份,可以直接把数据恢复到事故发生前的最近正常的时间点。
编辑
有了备份后的老数据,还要考虑恢复这个时间点后新增的用户数据。
有很多种恢复策略,我优先选择了逻辑最简单的策略:直接更新用户 updateTime > '2023-07-20 10:00:00' 的数据,根据 id 点对点覆盖除了 userRole 之外的数据列;如果没有对应的 id,新增一条数据。也就是使用类似 saveOrUpdate
的方法。
理想很丰满,现实很残酷。万万没想到,由于 updateTime 是一个发生数据修改时自动更新的字段,导致所有的数据 updateTime 全是最新的,相当于要把数据库全量的数据都去比较一遍。
单线程还是太慢了,于是我用并发编程的方式改进了同步的过程。先把所有用户分组,然后多线程同时执行 saveOrUpdateBatch 方法。
二、事后复盘完善
2.1 控制操作权限
为了防止用户执行 update、delete 操作时不小心漏掉了 where 条件、直接更新全量数据,企业中一般是会禁止不带 where 条件的修改操作的。
出现这次的事故后,我也立刻给 MySQL 开启了 sql_safe_updates 配置:
编辑
缺少 where 条件的更新会直接触发下列报错:
编辑
之前为什么没加?主要是因为以前都是自己一个人开发系统,而且会有需要全量更新的场景,图省事儿。
2.2 生产环境隔离
正常情况下,不应该允许直接在本地连接和操作线上数据库的数据。而是需要先编写代码、提交代码审核、发布上线后,再执行修改操作。
像这次的事故,如果员工不是本地直接更新数据库,而是提交代码给我看一下,我大概率就会发现他少写了更新条件,就能防止了。
其实之前在大公司的时候,我们都会严格注意这些事项的。但之所以现在的小公司的项目是允许员工在本地连接线上的,想必大家也能猜到原因 —— 业务规模小、人数少,直接在同一个库开发会方便一些。
但如果项目的规模上来了,一定要做好多套环境的隔离,本地环境、测试环境、预发布环境、线上环境都要严格区分了。
2.3 SQL 审批
之前在大公司的时候,想要修改关键库的数据,不能直接执行 SQL 语句,而是要先把 SQL 语句提交到审核平台,等你的领导和数据库运维确认没问题后,才能执行。这样每条 SQL 都是至少有 2 个人看过的,能够大大增加安全性。
曾经我觉得这种机制很麻烦,但经历过一些血泪教训后,才意识到这个环节真的是泰裤辣!
2.4 数据库审计
数据库审计是指记录和监控数据库的访问及 SQL 语句执行情况,从而精细化风险控制,提高数据安全性。
可以自己在数据库配置(比如开启日志、使用审计插件等),也可以使用第三方云服务自带的审计规则配置。
2.5 提升风险意识
最不需要技术,却也是最重要的一点,那就是要让团队的所有同学意识到这件事情带来的风险、问题的严重性。
因为你永远叫不醒一个装睡的人,同理,再多的防护也限制不了本身就想搞事的人。
所以这件事情是我和这位员工共同的责任,作为惩罚,我们决定请其他同事喝奶茶。就这么愉快地决定了~
三、总结
这次事件再次强调了在进行数据库操作时,特别是更新、删除、赋予权限等敏感操作时,必须非常谨慎。任何的疏忽都可能导致严重的后果,如本次事件中,用户权限的错误更新导致了所有用户都拥有了管理员权限,这无疑是一个巨大的安全漏洞。
对于开发人员,如员工小A,应进行定期的代码审查和单元测试,确保此类问题不再发生。同时,对于此类可能产生严重后果的操作,应该采用更严格的审批流程,如需要多人同时审核,以确保操作的正确性和安全性。
此外,对于数据库操作,应该有完善的备份和恢复机制,以便在发生错误时能够迅速恢复到正常状态。对于用户数据的更改,也应该有详细的记录和审计机制,以便追踪和管理可能出现的问题。
总的来说,这次事件提醒我们在进行任何数据库操作时,都应该小心谨慎,避免因疏忽导致严重的后果。同时,对于可能产生严重后果的操作,应该采用更严格的审批流程和备份恢复机制,以确保数据的安全性和完整性。