菜单开关

周梦康 发表于 2022-04-22 289 次浏览

很久没更新跑路笔记了,这次的 bug 藏得不深,但是祖传代码的问题,最终云产品工具分析反推定位问题的案例。故事是这样的

找不到的更新

跑路哥接手一坨祖传代码,遇到一个 bug 找了半天没找到问题,有数据被莫名篡改怎么样定位不到问题,差点崩溃。因为有些更高的权限只有我有,也就把我拉进了群,我刚进群就看到

运营人员群里咆哮“怎么回事,我的数据怎么被清空了,谁删了我的数据!!!”

虽然是一个很低频的后台功能,但是不修复也没法给别人运营用啊。

大概了解了下背景,表有三个字段,id,a,v

idav
123456780
123556780

代码是这样的

Integer aValue = xxx; // 前面逻辑计算得到
Example example = new Example(xxxDO.class);
Example.Criteria criteria = example.createCriteria();
criteria.andEqualTo("a", aValue);
List<xxxDO> xxList = xxxMapper.selectByExample(example);

XxxDO xxxDO = new XxxDO();
xxxDO.setv((byte) 0);
xxxDO.setGmtModified(date);
if (CollectionUtils.isNotEmpty(xxList)) {
    xxxMapper.updateByExampleSelective(xxxDO, example);
}

被篡改的数据是 a=5678筛选出来的两行数据,所以我根据一些 java 里面的 sql 日志,根本没有找到

update xxx_table set v=0 where a=5678;

定位问题

那就比较诡异了,最终实在没办法了,通过阿里云 RDS 控制里的 sql 洞察,根据某些关键字搜索更新表的 sql 执行记录。明显发现到了一条一次更新了692行的执行记录
类似于

update xxx_table set v=0

没有任何条件限制,这就非常严重了!!!
通过追踪代码分析上下文,确实存在 Integer aValuenull 的情况。

查看 ORM 源码发现

criteria.andEqualTo("field_xxx", null);

如果这个值是 null 等于 update 不加这个条件,太坑爹了。使用开源代码需谨慎。

问题定位了,修复线上 bug 是肯定的,另一个救命稻草就是 service 方法的入参返回值的日志。

也只能通过捞出运营设置值对应的方法的入参日志来做补偿了,还好逻辑不复杂,很多时候数据都不好订正。

大家使用云数据库记得开这个 sql 审计,说不定某些时候就能派上用场了。

复盘

  1. 微服务日志记录不差那么点性能,就把入参出参记录下吧,极个别的出参特别长的字符串可以特殊处理,比如异步精简之后打印
  2. 日志保存久点,说不定明天就用上了,我用到的次数还真不少
  3. 云数据库 SQL 审计真不错,推荐开启,不知道有没有一次更新超过多行就报警的功能
  4. 更新 sql 最好根据主键更新更安全

👇 下面是我的公众号,高质量的博文我会第一时间同步到公众号,给个关注吧!

评论列表