Java请求中关于如何避免防重放攻击

重放攻击介绍

防止重放攻击的方法是使用不重数

  1. 加随机数
    该方法优点是认证双方不需要时间同步,双方记住使用过的随机数,如发现报文中有以前使用过的随机数,就认为是重放攻击。缺点是需要额外保存使用过的随机数,若记录的时间段较长,则保存和查询的开销较大。
  2. 加时间戳
    该方法优点是不用额外保存其他信息。缺点是认证双方需要准确的时间同步,同步越好,受攻击的可能性就越小。但当系统很庞大,跨越的区域较广时,要做到精确的时间同步并不是很容易。)

我的做法是:
方法: 时间戳校验 + mac签名校验 双重验证
具体是:
在项目里面,当客户端请求我服务器的时候,会给我传递一些公共参数,比如客户端请求的时间戳,以及加密后的mac签名。
第一步: 我在拦截器里面拿到请求时间戳之后,转换为毫秒值,这时候我服务器端也会生成一个当前时间毫秒值,做差值比较
if((当前时间-请求时间)>60000 );//60秒
那就认为请求报文已经被拦截,正在攻击,说明此请求异常,结束请求。
如果是<60000毫秒 ,暂时认为是符合的(有疑问往下看),让请求继续往下走。
3,使用请求序列号方式(可代替mac签名)
虽然使用时间戳方式可以在一定程度上控制重放攻击,但是存在时间限制。在指定时间窗口下,任然不可避免会受到攻击。
服务器端和客户端约定一个序列号生成算法(保证全局唯一性),客户端每次请求时都需要携带请求序列号。
服务器端接到请求时,先验证序列号是否合法,不合法直接拒绝。否则查看缓存中是否已经存在过该序列号,若已经存在,表明该请求已经被处理,不允许再次调用。
本次处理完毕,将请求序列号缓存。
这样可以保证一个序列号对应的请求只会被处理一次,相对比较安全地杜绝了重放攻击。
比较时间差值:

		SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmss");

		long req_time = simpleDateFormat.parse("20190625093842").getTime();
		long now_time =  new Date().getTime();
		
		(now_time-req_time)>60000
 在步骤一的基础上, 已经判断了时间差值, 不安全,因为一秒钟就可能被请求很多次,所以还需要进行mac验证。
   这时候我借助了cache缓存器 (CacheManager类) , 思路是:
     把客户端请求mac签名作为key,客户端请求时间戳作为value,保存到cache里面,
     cache(mac, time, cache名字)  到cache里面。
     
      此时已经保存,然后下次客户客户端请求,先根据加密后的mac签名和缓存名去cache里面取值,如果能拿到请求时间key, 不为空,就可以断定正在被重放攻击(数据重复),需要拦截下来。如果根据时间戳拿不到mac,说明正常请求,然后把正常请求的mac,请求时间戳 保存到cache里面就行了。
      ![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/58538ec638945525726de8ab46b84c66.png)
      timeToLiveSeconds="60":  缓存里60秒后会失效,这样就不会一直累加到缓存里面(当然有redis也可以借助redis).  大概就是这么个步骤。

在这里插入图片描述在这里插入图片描述
在这里插入图片描述

       											do-time:2019/6/25  
       											笔者:dk
  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
防重攻击是一种常见的网络安全攻击,主要是为了止攻击者在网络通信过程重复发送已经发送过的请求,从而引发一些安全问题。下面是一个简单的Java代码示例,展示如何使用时间戳和随机数来重放攻击。 ```java import java.util.HashMap; import java.util.Map; public class AntiReplayAttack { private static Map<String, Long> requestMap = new HashMap<>(); public static boolean checkRequest(String requestId) { Long timestamp = requestMap.get(requestId); if (timestamp != null && System.currentTimeMillis() - timestamp <= 1000) { // 1秒内同一请求ID的请求被视为重复请求,拒绝处理 return false; } else { requestMap.put(requestId, System.currentTimeMillis()); return true; } } public static void main(String[] args) { String requestId = "123456"; boolean isValidRequest = checkRequest(requestId); System.out.println("Request " + requestId + " is valid: " + isValidRequest); } } ``` 在该示例,我们维护一个请求 ID 到请求时间戳的映射,当一个新请求到达时,我们首先检查该请求 ID 是否存在于映射表,如果存在,则检查当前时间戳与上次请求时间戳之间的时间差是否小于等于1秒。如果是,则认为这是一个重复请求,直接返回false;否则,更新请求时间戳,并返回true。 你可以根据实际需求进行调整,如增加随机数来增加安全性,或者将映射表存储在数据库以支持分布式应用。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值