redis防止黑客恶意攻击的简单办法

1.在redis中放入有用户标识的key,每次用户操作时都会根据用户标识的key去匹配一下,匹配上就能操作,匹配不上就拒绝。

下面的代码是商品秒杀场景,根据用户id和商品id去生成一个标识,然后放入redis缓存中。

@Override
    public String getMd5(Integer id,Integer userid){
        //检验用户的合法性
        User user = userMapper.findById(userid);
        if(user == null) throw new RuntimeException("用户信息不存在!");
        log.info("用户信息:[{}]",user.toString());
        //检验商品的合法性
        Stock stock = stockMapper.checkStock(id);
        if(stock == null) throw new RuntimeException("商品信息不合法!");
        log.info("商品信息:[{}]",stock.toString());
        //生成hashkey
        String hashKey = "KEY_"+userid+"_"+id;
        //生成md5//这里!QS#是一个盐 随机生成
        String key = DigestUtils.md5DigestAsHex((userid+id+"!Q*jS#").getBytes());
        stringRedisTemplate.opsForValue().set(hashKey,key,3600, TimeUnit.SECONDS);
        log.info("Redis写入:[{}][{}]",hashKey,key);
        return key;
    }

用户要秒杀商品时,根据用户id和商品id去redis查找有没有对应的签名,如果有则放行,没有就抛出异常。

 @Override
    public int kill(Integer id, Integer userid, String md5) {
        //校验redis中秒杀商品是否超时
        if(!stringRedisTemplate.hasKey("killphone")){
            throw new RuntimeException("当前商品的抢购活动已经结束啦~~");
        }
        //先验证签名
        String hashKey = "KEY_"+userid+"_"+id;
        String s = stringRedisTemplate.opsForValue().get(hashKey);
        if(s==null) 
        	throw new RuntimeException("没有携带验证签名,请求不合法!");
        if(!s.equals(md5))
            throw new RuntimeException("当前请求数据不合法,请稍后再试!");
        //校验库存
        Stock stock = checkStock(id);
        //更新库存
        updateSale(stock);
        //创建订单
        return createOrder(stock);
    }

2.用redis根据用户id在一定时间范围内统计用户访问次数,超过一定次数就限制访问。

下面这个类是在redis中保存和查询用户访问次数。

@Slf4j
@Service
@Transactional
public class UserServiceImpl implements UserService {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public int saveUserCount(Integer userId) {
         //根据不同用户id生成调用次数的key
        String limitKey = "LIMIT"+"_"+userId;
        //获取redis中指定key的调用次数
        String limitNum = stringRedisTemplate.opsForValue().get(limitKey);
        int limit = -1;
        if(limitNum == null){
            //第一次调用放入redis中设置为0
            stringRedisTemplate.opsForValue().set(limitKey,"0",3600, TimeUnit.SECONDS);
         }else{
            //不是第一次调用每次+1
            limit = Integer.parseInt(limitNum)+1;
            stringRedisTemplate.opsForValue().set(limitKey,String.valueOf(limit),3600,TimeUnit.SECONDS);
        }
        return limit;
    }

    @Override
    public boolean getUserCount(Integer userId) {
        //根据userid对应key获取调用次数
        String limitKey = "LIMIT"+"_"+userId;
        //根据用户调用次数的key获取redis中调用次数
        String limitNum = stringRedisTemplate.opsForValue().get(limitKey);
        if(limitNum == null){
            //为空直接抛弃说明key出现异常
            log.error("该用户没有访问申请验证值记录,疑似异常");
            return true;
        }
        return Integer.parseInt(limitNum) > 10;//false代表没有超过,true代表超过
    }
}

当用户在一定时间内访问次数达到限制次数,就不让用户再去访问了。

//开发一个秒杀方法 乐观锁防止超卖+令牌桶算法限流+md5签名(hash接口隐藏)+单用户访问频率限制
    @GetMapping("killtokenmd5limit")
    public String killtokenmd5limit(Integer id,Integer userid,String md5){
        System.out.println("秒杀商品的id="+id);
        //加入 令牌桶的限流措施
        if(!rateLimiter.tryAcquire(3, TimeUnit.SECONDS)){
            log.info("抛弃请求:抢购失败,当前秒杀活动过于火爆,请重试");
            return "抛弃请求:抢购失败,当前秒杀活动过于火爆,请重试!";
        }
        try{
            //单用户调用接口的频率限制
            int count = userService.saveUserCount(userid);
            log.info("用户截止该次的访问次数为:[{}]",count);
            //进行调用次数的判断
            boolean isBanned = userService.getUserCount(userid);
            if(isBanned){
                log.info("购买失败,超过频率限制!");
                return "购买失败,超过频率限制!";
            }
            //根据秒杀商品id 去调用秒杀业务
            int orderId = orderService.kill(id,userid,md5);
            return "秒杀成功,订单id为:"+String.valueOf(orderId);
        }catch(Exception e){
            e.printStackTrace();
            return e.getMessage();
        }
    }
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值