【卧槽这答题抽奖这么烂????以前测过吗】

问题虽然很常见,也在这儿记录分享一下吧

项目简述:
最近我收到个任务是要将我们的答题活动,对接放到微信公众号中去,微信和app能够同时参加活动、抽奖。搬迁之后复测,看了下代码,我滴妈,问题太多了!(代码是21年写的,非常混乱逻辑全在controller的method里面,估计这个author现如今已经(成大牛)退休了吧!)


我发现的一些安全问题

  • 重复答题
  • 参加答题计次不对
  • 重复领奖
  • 库存超发
  • 前后端状态码的约定问题

问题分析、解决方案:

这些问题对于C端来说都是非常见的问题,无非就是增加校验,加分布式锁嘛

  • 重复答题
    一直答题的原因是后端接口没有做校验,因此可以一直调用接口一直答题抽奖。解决方式:后端把校验逻辑加上,加上校验逻辑之后还通过setIfAbsent对同一用户操作加了锁(防止并发问题)

    // 业务逻辑校验
    if(!check(data)){
    	return Response.error(503, "服务器繁忙,请稍后再试!");
    }
    //防止同一个用户重复提交,并发绕过校验的问题
    if(!redisTemplate.opsForValue().setIfAbsent(userId,userId, Duration.ofMillis(1000))){
       return Response.error(503, "服务器繁忙,请稍后再试!");
     }
    

    各位大佬也看看setIfAbsent用得没啥问题吧!!!!!

  • 参加答题计次不对
    原来的逻辑如下(伪代码):

    //从map中获取次数,获取成功则加1 
    //static HashMap<String, AtomicInteger> countMap= new HashMap<String, AtomicInteger>();
    
    if (countMap.get(key) == null) {
            // 統計每日答題記錄
            answerTimes = answerActivityRecordService.count(wrapper);
            ActivityMemoryObject.answerLimit.put(key, new AtomicInteger(answerTimes));
    } else {
            AtomicInteger curent = countMap.get(key);
            answerTimes = curent.incrementAndGet();
    }
    //校验通过执行业务逻辑
    if(checkTimes(answerTimes)){
    	save();
    }
    

    咋眼看上去没啥问题,仔细看也没啥问题。如果正常操作的话确实没问题。问题就在没执行业务代码次数也加1了,比如我这个活动参加次数限制是5次,可能我缓存的参加都达到10多次了,我去数据库把活动次数增加,这时候再去参加活动,对比次数就出问题了(当然这种情况只有测试的时候才有!)。

    对于上面的逻辑做了两点调整
    1.用HashMap 只有在系统重启的时候才会被清除,使用弱引用线程安全的map这样jvm在执行gc的时候就会清除缓存,防止缓存堆积:countMap= new ConcurrentReferenceHashMap<String, AtomicInteger>();
    2.执行了业务才加1

  • 重复领奖
    接口没有做以领取的校验,导致一直掉接口可以一直领取,修复方式请求接口的时候查询一次这条数据的领取状态,如果不是未领取则直接返回。这样改了之后还有可能存在并发问题,多个线程同时进来这个校验逻辑肯定会校验通过。领取成功之后不是还要更新状态吗,这个地方我也做了如下修改,利用了一个mysql update 实现一个乐观锁

    //修改前,直接根据id更新数据
    updateById(id);
    //其他业务逻辑
    down();
    
    //修改后,条件增加 期望的状态值,算是一个乐观锁吧
    if(!updateByIdAndStatuas(id,originStatus)){
    	throw new RuntimeExcption("你已经抽过奖了!");
    }
    down();
    
  • 库存超发
    以前啥限制也没做,这里加了一个redis的分布式锁,获取锁失败进行一个事物回滚!

  • 前后端状态码的约定问题
    后端都报错了,返了50x状态码了,前端还在从里面拿数据,接着下一步操作!哎难受哦!传些undifined到后端。。。。。。。。


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不务专业的程序员--阿飞

兄弟们能否给口饭吃

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值