重放攻击

重放攻击是指黑客通过抓包的方式,得到客户端的请求数据及请求连接,重复的向服务器发送请求的行为。 比如你有一个 “购买” 的操作,当你点击购买按钮时,向服务器发送购买的请求。而这时黑客对你的请求进行了抓包,得到了你的传输数据。 因为你填写的都是真实有效的数据,是可以购买成功的,因此他不用做任何改变,直接把你的数据再往服务器提交一次就行了。这就导致了,你可能只想购买一个产品的,结果黑客重放攻击,你就购买了多次。如果是用户操作的话,肯定就会莫名奇妙:怎么购买了那么多同样的产品,我只买了一个啊? 所以,重放攻击的危害还是挺大的,特别是涉及到金钱交易时,因此防重放攻击在电商项目中是必不可少的。

解决方案

时间戳(tamp) + 数字签名(sign)。 也就是说每次发送请求时多传两个参数,分别为 tamp 和 sign。比如

原先请求为 http://127.0.0.1/api/buyproduct

修改之后为 http://127.0.0.1/api/buyproduct?tamp=1403149835&sign=945bf36r046bd84df2985ad625c9f92415eccd1w

数字签名的作用是为了确保请求的有效性。因为签名是经过加密的,只有客户端和服务器知道加密方式及Key,所以第三方模拟不了。我们通过对sign的验证来判断请求的有效性,如果sign验证失败则判定为无效的请求,反之有效。 但是数字签名并不能阻止重放攻击,因为黑客可以抓取你的tamp和sign(不需做任何修改),然后发送请求。这个时候就要对时间戳进行验证。

时间戳的作用是为了确保请求的时效性。我们将上一次请求的时间戳进行存储,在下一次请求时,将两次时间戳进行比对。如果此次请求的时间戳和上次的相同或小于上一次的时间戳,则判定此请求为过时请求,无效。因为正常情况下,第二次请求的时间肯定是比上一次的时间大的,不可能相等或小于。

有人会问,我直接用时间戳不就行了,为什么还要数字签名?因为黑客可能对请求进行抓包,然后修改时间戳为有效的时间戳值。我们的数字签名采用 tamp+key 进行组合加密,即使黑客修改了 tamp ,但是由于黑客不知道key,所以 sign 验证这步就成功的阻止了黑客的请求。

实例代码

加密方式采用 SHA1,SHA1加密方法进行了封装,写成了string的扩展方法。

/// <summary>
/// 数字签名
/// </summary>
/// <param name="tamp">时间戳(由客户端传入)</param>
/// <param name="key">Key</param>
/// <returns></returns>
private string Sign(string tamp, string key)
{
string txt = tamp + "|" + key; //在每个参数中间加了个 "|" ,增加复杂度
string sign = txt.GetSha1();
return sign;
}

验证方法, 客户端的加密方式和服务端是一样的,如果两者的加密结果不一致,则验证失败。 如果客户端是js,一定要对js做代码混淆,禁止右键等。因为我是用Session存储上一次请求的时间戳的,而Session是会过时的,当Session过时时黑客再进行攻击,就会得手,所以限制请求有效期为30秒。

/// <summary>
/// 检查请求是否有效,防重放
/// </summary>
/// <param name="tamp">时间戳(由客户端传入)</param>
/// <param name="key">Key</param>
/// <param name="sign">验签(由客户端传入)</param>
/// <returns></returns>
private bool CheckRequest(string tamp, string key, string sign)
{
//验签(比对客户端的加密结果和服务端的加密结果,如果不相等,则验签失败)
if (sign.ToUpper() != Sign(tamp, key).ToUpper()) return false; //得到当前时间戳
DateTime DateStart = new DateTime(, , , , , );
int nowTamp = Convert.ToInt32((DateTime.Now - DateStart).TotalSeconds);
   if ((nowTamp - int.Parse(tamp)) > 30) return false; //因为Session可能过时,所以限定请求有效时间为30秒

//得到上一次的时间戳
string prevTamp = Session["tamp"] as string;

//判断是否为空,为空说明是第一次请求
if (!string.IsNullOrWhiteSpace(prevTamp))
{
if (int.Parse(tamp) > int.Parse(prevTamp))
{
Session["tamp"] = tamp;
return true;
}
else
{
return false;
}
}
else
{
Session["tamp"] = tamp;
return true;
}
}

最新文章

  1. Mac OS、Ubuntu 安装及使用 Consul
  2. PHP用户名用星号处理
  3. 使用Genymotion安装APK出现错误INSTALL_FAILED_CPU_ABI_INCOMPATIBLE的解决办法
  4. 发短信的主要代码(SmsManger)
  5. C# lazy&lt;T&gt;的用法
  6. 2.1 实践篇:使用ping来检测网速
  7. Windows Azure系列-- 配置Azure Power Shell
  8. openresty 中mime.types 文件缺失问题,无法展示图片
  9. SSM-SpringMVC-15:SpringMVC中小论注解式开发之通配符篇
  10. 聊天框Demo:DotNetCore+ActiveMQ+Mqttjs 实现前后台消息监听
  11. golang 结构体中的匿名接口
  12. FPGA學習筆記(肆)--- Star Test Bench Template Writer
  13. luogu P3198 [HNOI2008]遥远的行星
  14. Apache Kafka监控之Kafka Web Console
  15. vue基础项目安装教程
  16. Linux下 mkdir 命令详解
  17. [PyTorch]论文pytorch复现中遇到的BUG
  18. django参考博客学习
  19. ubuntu下 pycharm使用andcoda下的tensorflow
  20. UVA 548(二叉树重建与遍历)

热门文章

  1. 【5】JMicro微服务-熔断降级
  2. 基于鸢尾花数据的PCA降维处理
  3. DockerFile(保你会版本)(七)
  4. 11-01 Java 开发工具 eclipse从下载、安装到实际使用的详细教程
  5. Oracle 扩展表空间大小的几种方式
  6. 微信小程序交流群,欢迎加入,其中微信小程序开发群、Jenkins开发群是有问必答群
  7. 一口一口吃掉Hexo(三)
  8. iis7 bug解决
  9. ADB命令获取Android UID
  10. 解读Secondary NameNode的功能