zoukankan      html  css  js  c++  java
  • 如何解决重复下单的问题?(下单防重,重放攻击)

    如何解决重复下单的问题?(下单防重,重放攻击)

    问题来源:

    近日发现某些用户对一些商品进行多次下单,而且比较频繁,而且下单时间都在同一秒内,怀疑产生重复请求

    问题描述:

    用户在商品页面,多次点击下单按钮,后台怎么知道是用户对一个商品进行多次下单,还是人工误操作或者客户端异常进行重复请求下单了呢?

    解决方案:

    1. 进入商品页面,就是下单页面的时候,产生一个不重复的随机数。
    2. 下单的时候把这个随机数带上
    3. 下单校验的时候,利用Redis缓存锁,先锁这个随机数,再做业务处理,做完再释放。

    问题升级:

    如果客户端重复的下单请求过多,或者后台处理过快,就会产生所谓的重放攻击。
    如,客户端请求模拟
    请求A 20:18:01 xxx/order?storeid=1&randomNum=abcd123 用户下单
    请求A 获得锁成功,开始处理
    请求B 20:18:01 xxx/order?storeid=1&randomNum=abcd123 用户下单
    请求B 获得锁失败
    请求C 20:18:01 xxx/order?storeid=1&randomNum=abcd123 用户下单
    请求C 获得锁失败
    请求A 下单成功,释放锁
    请求D 20:18:01 xxx/order?storeid=1&randomNum=abcd123 用户下单
    请求D 获得锁成功,开始处理
    请求D 下单成功,释放锁

    针对同一个随机数randomNum=abcd123居然下单成功2次,这就是重复攻击带来的危害

    问题升级,解决方案:

    1. 下单校验的时候,利用Redis缓存锁,先锁这个随机数,锁成功之后,判断随机数是否曾经处理过,如果没有就把随机数加入缓存设置时长为X,再做业务处理,做完再释放
    /**
         * 获得锁
         * @param lockId
         * @return
         */
        public boolean getLock(String lockId) {
            try {
    
                String KEY_LOCK_ID_="LOCK_ID_";
                String KEY_LOCK_HIS_ID_="LOCK_HIS_ID_";
                Boolean success = redisTemplate.opsForValue().setIfAbsent(KEY_LOCK_ID_+lockId, "lock");
                //解决重放攻击
                if(success != null && success){
                  if(hasKey(KEY_LOCK_HIS_ID_+lockId)){
                      success = false;
                      logger.error("【REDIS操作】【获得锁失败】【已存在历史锁码】【怀疑重放攻击:"+lockId+"】");
                  }else{
                      success = true;
                      set(KEY_LOCK_HIS_ID_+lockId,lockId,60*60*24);
                  }
                }
                return success;
            } catch (Exception e) {
                logger.error("【REDIS操作】【获得锁错误】",e); 
                return false;
            }
        }
    
        /**
         * 释放锁
         * @param lockId
         */
        public void releaseLock(String lockId) {
            try {
                String KEY_LOCK_ID_="LOCK_ID_";
                redisTemplate.delete(KEY_LOCK_ID_ + lockId);
            } catch (Exception e) {
                logger.error("【REDIS操作】【释放锁错误】",e); 
            }
        }
    

      

    问题描述:用户下订单购买,因为各种原因(网络卡,快递点击等)重复提交2个或者以上一模一样的订单,由于是同时提交的,第一个订单执行扣款生成订单未完成时候,第二个已经进来了,导致付一笔钱购买了2次或多次商品 解决方案:

    1、缓存lock,缓存此用户的操作行为,注意紧紧缓存操作的标志,下次进入判断此标志是否存在,存在即不进入数据库事务

    2、应用程序application lock,和1相比,会阻塞其他用户的正常行为

    3、模仿银行扣款机制,数据表建一个随机唯一标志,每次请求带上这个标志,操作的同时进行修改这个标志

    4、应用程序生成唯一标志,数据库做字段的唯一索引

    5、扣款为负数的事务进行回滚

    6、使用事务的隔离级别

    7、使用redis的incr控制用户的并发数,memcache的add也可以实现这种效果,memcached借助cas

  • 相关阅读:
    1012 The Best Rank (25 分)(排序)
    1011. World Cup Betting (20)(查找元素)
    1009 Product of Polynomials (25 分)(模拟)
    1008 Elevator (20 分)(数学问题)
    1006 Sign In and Sign Out (25 分)(查找元素)
    1005 Spell It Right (20 分)(字符串处理)
    Kafka Connect 出现ERROR Failed to flush WorkerSourceTask{id=local-file-source-0}, timed out while wait
    flume、kafka、avro组成的消息系统
    Java23种设计模式总结【转载】
    Java编程 思维导图
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/13365896.html
Copyright © 2011-2022 走看看