当我们开发一款App的时候,App需要跟后台服务进行通信获取或者提交数据。如果我们没有完善的安全机制则很容易被别用心的人伪造请求而篡改数据。

所以我们需要使用某种安全机制来保证请求的合法。现在最常用的办法是给每个http请求添加一个签名,服务端来验证签名的合法性,如果签名合法则执行响应的操作,如果签名非法则直接拒绝请求。

签名算法

签名算法一般都使用Hash散列算法,常用的有MD5,SHA系列算法。这些算法可以根据不同的输入,计算出不同的结果,而且碰撞的概率很低。

签名算法跟加密算法不是一回事。很多同学都会说使用MD5加密一下,其实这是错误的。签名算法不能恢复原来的数据,因为它本身并不包含原来数据的信息。

而加密方法不同,加密方法是可以根据加密结果重新推算出原来的数据的。

HMAC SHA作为一种更加安全的签名算法,使用一个Key来影响签名的结果。这样同样的输入配合不同的Key可以得出不同的签名,更加安全。

 public static string HmacSHA256(string secretKey,string plain)
{
var keyBytes = Encoding.UTF8.GetBytes(secretKey);
var plainBytes = Encoding.UTF8.GetBytes(plain); using (var hmacsha256 = new HMACSHA256(keyBytes))
{
var sb = new StringBuilder();
var hashValue = hmacsha256.ComputeHash(plainBytes);
foreach (byte x in hashValue)
{
sb.Append(String.Format("{0:x2}", x));
}
return sb.ToString();
}
}

签名的参数

有了签名算法,那么我们签名的内容哪里来呢?

一般我们使用http请求的queryString然后加上时间戳还有随机数来作为签名的参数。

 public static string MakeSignPlain(SortedDictionary<string,string> queryString,string time,string random )
{
var sb = new StringBuilder();
foreach (var keyValue in queryString)
{
sb.AppendFormat("{0}={1}&", keyValue.Key, keyValue.Value);
}
if (sb.Length>1)
{
sb.Remove(sb.Length - 1, 1);
}
sb.Append(time);
sb.Append(random); return sb.ToString().ToUpper();
}

验证签名

验证签名就是简单的比较服务端生产的签名跟客户端生产的签名是否一直。

要注意的一点是最好验证下时间戳,跟服务端时间比较前后不能相差5分钟。这也是一个简单的防Replay Attack的手段。

 public static bool Valid(string requestSign,string signPlain,string time, string secretKey)
{
if (string.IsNullOrEmpty(time)||string.IsNullOrEmpty(requestSign)||string.IsNullOrEmpty(signPlain))
{
return false;
}
//is in range
var now = DateTime.Now;
long requestTime =0;
if (long.TryParse(time,out requestTime))
{
var max = now.AddMinutes(5).ToString("yyyyMMddHHmmss");
var min = now.AddMinutes(-5).ToString("yyyyMMddHHmmss");
if (!(long.Parse(max) >= requestTime && long.Parse(min) <= requestTime))
{
return false;
} }
else
{
return false;
} //hashmac
var sign = Encryption.HmacSHA256(secretKey, signPlain); return requestSign.Equals(sign, StringComparison.CurrentCultureIgnoreCase);
}

ApiController基类

有了上面这些铺垫我们就可以在基类完成签名的验证了。客户端需要把上面提到的时间戳,随机数,签名和客户端的ID放入http请求的headers里面。

我们在基类的OnActionExecuting里取出这些数据组合成签名的参数,然后根据客户端ID获取签名的Key,然后使用同样的签名算法计算签名。并且比较客户端的签名跟服务端的签名是否一致。

这里就不演示了。

预防Replay Attack

预防重放攻击主要有两点:

  • 校验时间戳的范围

    时间戳跟服务器时间相差在一个合理的范围内视为合法。
  • 缓存签名

    每次请求都去判断下签名是否出现过。如果出现过则视为非法请求。

    因为有时间戳跟随机数的存在,所以理论上每次请求的签名是不可能重复的。

客户端调用

这里演示一下C#签名并且调用http接口的代码

 [TestMethod()]
public void GetUserTest()
{
string url = "http://localhost:8090/api/test/GetUser";
string userId = "A39891D4-6CEF-4538-A562-3A422CA9C17A";
string appId = "100001";
string secretKey = "M/vkPOWXgBa7GnRd73t7j+jsKfbZtb+f";
string rumdon = Guid.NewGuid().ToString();
string time = DateTime.Now.ToString("yyyyMMddHHmmss"); //make signture plain text
var sortDict = new SortedDictionary<string, string>()
{
{"userId",userId }
};
var signPlain = new StringBuilder();
foreach (var keyValue in sortDict)
{
signPlain.AppendFormat("{0}={1}&", keyValue.Key, keyValue.Value);
}
if (signPlain.Length > 1)
{
//remove last &
signPlain.Remove(signPlain.Length - 1, 1);
}
signPlain.Append(time);
signPlain.Append(random); Console.WriteLine("sign plain:{0}", signPlain.ToString().ToUpper());
//make sign
var sign = Encryption.HmacSHA256(secretKey, signPlain.ToString().ToUpper());
Console.WriteLine("sign:{0}", sign); string requestUrl = string.Format("{0}?{1}={2}", url, "userId", userId);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestUrl);
request.Method = "GET";
//add headers
request.Headers.Add("time", time);
request.Headers.Add("appId", appId);
request.Headers.Add("random", random);
request.Headers.Add("sign", sign);
//
//start request
try
{
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
var responseStream = response.GetResponseStream();
if (responseStream != null)
{
using (StreamReader reader = new StreamReader(responseStream))
{
var content = reader.ReadToEnd(); Console.WriteLine(content);
}
}
}
}
catch (WebException ex)
{
using (HttpWebResponse response = (HttpWebResponse)ex.Response)
{
var responseStream = response.GetResponseStream();
if (responseStream != null)
{
using (StreamReader reader = new StreamReader(responseStream))
{
var content = reader.ReadToEnd();
Console.WriteLine(content);
}
}
}
}
}

使用签名来保证ASP.NET MVC OR WEBAPI的接口安全的更多相关文章

  1. C#/ASP.NET MVC微信公众号接口开发之从零开发(四) 微信自定义菜单(附源码)

    C#/ASP.NET MVC微信接口开发文章目录: 1.C#/ASP.NET MVC微信公众号接口开发之从零开发(一) 接入微信公众平台 2.C#/ASP.NET MVC微信公众号接口开发之从零开发( ...

  2. 给Asp.Net MVC及WebApi添加路由优先级

    一.为什么需要路由优先级 大家都知道我们在Asp.Net MVC项目或WebApi项目中注册路由是没有优先级的,当项目比较大.或有多个区域.或多个Web项目.或采用插件式框架开发时,我们的路由注册很可 ...

  3. C#/ASP.NET MVC微信公众号接口开发之从零开发(三)回复消息 (附源码)

    C#/ASP.NET MVC微信接口开发文章目录: 1.C#/ASP.NET MVC微信公众号接口开发之从零开发(一) 接入微信公众平台 2.C#/ASP.NET MVC微信公众号接口开发之从零开发( ...

  4. AJAX跨域调用ASP.NET MVC或者WebAPI服务

    关于AJAX跨域调用ASP.NET MVC或者WebAPI服务的问题及解决方案 作者:陈希章 时间:2014-7-3 问题描述 当跨域(cross domain)调用ASP.NET MVC或者ASP. ...

  5. 【转载】为ASP.NET MVC及WebApi添加路由优先级

    路由方面的: 转载地址:http://www.jb51.net/article/73417.htm Author:lijiao 这是一个对Asp.Net Mvc的一个很小的功能拓展,小项目可能不太需要 ...

  6. AJAX跨域调用ASP.NET MVC或者WebAPI服务的解决方案

    问题描述 当跨域(cross domain)调用ASP.NET MVC或者ASP.NET Web API编写的服务时,会发生无法访问的情况. 重现方式 使用模板创建一个最简单的ASP.NET Web ...

  7. ASP.NET MVC对WebAPI接口操作(添加,更新和删除)

    昨天<怎样操作WebAPI接口(显示数据)>http://www.cnblogs.com/insus/p/5670401.html 既有使用jQuery,也有使作HttpClient来从数 ...

  8. 关于AJAX跨域调用ASP.NET MVC或者WebAPI服务的问题及解决方案

      作者:陈希章 时间:2014-7-3 问题描述 当跨域(cross domain)调用ASP.NET MVC或者ASP.NET Web API编写的服务时,会发生无法访问的情况. 重现方式 使用模 ...

  9. ASP.NET MVC 4 WebAPI. Support Areas in HttpControllerSelector

    This article was written for ASP.NET MVC 4 RC (Release Candidate). If you are still using Beta versi ...

随机推荐

  1. OC整理1

    关于面向对象 看起来简单,好好体会其实有点深奥,初学的时候更感觉抽象,可能由于开发经验不足的关系吧,很难体会到面向对象的精髓. 放轻松,我们来用最直白得方式来探讨一下面向对象. 首先,编程是为了用计算 ...

  2. java学习笔记(3)之面向对象(1)

    下面来谈谈我对面向对象的一些理解和总结. 1.什么叫面向对象?我自己的理解就是一种编程思想,强调对象,是一种思考问题的思维模式.在学习面向对象的时候,我们要建立起自己面向对象的思维模式. (1).先整 ...

  3. Unity学习疑问记录之坐标体系

    [Unity3D的四种坐标系] 1.World Space(世界坐标):我们在场景中添加物体(如:Cube),他们都是以世界坐标显示在场景中的.transform.position可以获得该位置坐标. ...

  4. .NET 4.5.1 预览版新特性

    上个月的微软Build大会上宣布了.NET 4.5.1的推出,Heydarian的这个演讲题为".NET开发中的新内容",涵盖了.NET Framework中一些重要的新特性. H ...

  5. Microsoft .NET Framework 4.0.3版下载

    适用于 Microsoft .NET Framework 4 的更新 4.0.3,其中包含一系列新增功能,用于满足高端客户的功能需求和重要 .NET Framework 方案的需求. http://w ...

  6. Web高级征程:《大型网站技术架构》读书笔记系列

    一.此书到底何方神圣? <大型网站技术架构:核心原理与案例分析>通过梳理大型网站技术发展历程,剖析大型网站技术架构模式,深入讲述大型互联网架构设计的核心原理,并通过一组典型网站技术架构设计 ...

  7. 扩展Bootstrap Tooltip插件使其可交互

    最近在公司某项目开发中遇见一特殊需求,请笔者帮助,因此有了本文的插件.在前端开发中tooltip是一个极其常用的插件,它能更好向使用者展示更多的文档等帮助信息.它们通常都是一些静态文本信息.但同事他们 ...

  8. 从Undo,Redo谈命令模式

    一般的应用软件中,通常会提供Redo和Undo的操作,比如Paint.NET中的动作面板,Word中的撤销重做,一般我们按Ctrl-Z即可回退到上次操作. 要实现上面的这一功能,最直观的想法就是,我们 ...

  9. this的安身之处

    在JavaScript的大千世界中,this对象就像一个行踪不定.居无定所的浪子一般,它的生活仿佛可以随处而安,而内心却又似有着笃定的坚守,它就是这么有趣! 初学JavaScript时的我们,多多少少 ...

  10. Atitit.数据索引 的种类以及原理实现机制 索引常用的存储结构

    Atitit.数据索引 的种类以及原理实现机制 索引常用的存储结构 1. 索引的分类1 1.1. 按照存储结构划分btree,hash,bitmap,fulltext1 1.2. 索引的类型  按查找 ...