线上数据无缘无故被篡改, 排查并解决
起因
客户反映, 线上已有数据被篡改, 原本未填写的表单项多了值
排查
查操作日志表, 未找到相关修改记录的操作, 查对应新增修改 service, 也无查询相关数据的操作, 前端也同样排查了一遍, 排除了页面缓存或者并发问题
查找客户反映的字段, 以这些字段为条件查询被篡改表(表 B), 发现了 3 条记录, 其中一条记录为触发器(表 A)新增, 查看触发器, 新增触发器没有修改动作, 修改触发器存在修改本表(表 B)的动作
表 A 是第三方厂商操作的表, 这个表有 CRUD 动作时, 要同步我们的表 B, 所以 表 A 中存在触发器, 来对表 B 做操作
仔细查看 sql, 未发现问题, 但是当时我非常肯定的认为就是触发器的问题, 于是手动修改了上面查到的三条记录中触发器新增的那条记录(表 A), 果然, 三条记录(表 B)都会被 update
查看 update 语句, 是根据主键更新, 对比之后发现, 触发器的表(表 A)主键是 int 类型, 被篡改表(表 B)主键是 UUID(字符串), 结果当作为条件比较时, 会把字符串转型, 类似下面:
1
2
3
4
5
23MMSSD0-0EWE0ADAS00F-SDF >> 23
0MSDA-QW3213-ASD-ERT-HFGF >> 0
KKKAS-ASD-A-SD-A-DA-DS-A-D >> 0
恰巧触发器的那条记录 ID 是 5, 而另外两条的 UUID 起始字符也都是 5, 所以就导致作为对比时, 相等
解决
把触发器的 update 语句检索条件, 整型主键转成字符串在做对比, 类似下面:
1
where concat(pk_id, '') = obj_id;
至此问题得到解决
其他问题记录
mysql5.6 之前的版本, 建表时, datetime 不支持长度: datetime(3), 如果使用数据泵导出的 5.6 之后版本的 sql, 在导入到 5.6 之前的版本库时, 要把 (3) 这种字符删掉才好使