在很多项目中,因为webapi是对外开放的,这个时候,我们就要得考虑接口交换数据的安全性。

安全机制也比较多,如andriod与webapi 交换数据的时候,可以走双向证书方法,但是开发成本比较大,

今天我们不打算介绍这方面的知识,我们说说一个较简单也较常见的安全交换机制

在这里要提醒读者,目前所有的加密机制都不是绝对的安全!

我们的目标是,任何用户或者软件获取到我们的webapi接口url后用来再次访问该地址都是无效的!

达到这种目标的话,我们必须要在url中增加一个时间戳,但是仅仅如此还是不够,用户可以修改我们的时间戳!

因此我们可以对时间戳 进行MD5加密,但是这样依然不够,用户可以直接对我们的时间戳md5的哦,因些需要引入一个绝对安全

双方约定的key,并同时加入其它参数进行混淆!

注意:这个key要在app里和我们的webapi里各保存相同的一份!

于是我们约定公式: 加密结果=md5(时间戳+随机数+key+post或者get的参数)

下面我们开始通过上述公式写代码:

于由我的环境是asp.net mvc 的,所以重写一个加密类ApiSecurityFilter

1、获取参数

if (request.Headers.Contains("timestamp"))
timestamp = HttpUtility.UrlDecode(request.Headers.GetValues("timestamp").FirstOrDefault()); if (request.Headers.Contains("nonce"))
nonce = HttpUtility.UrlDecode(request.Headers.GetValues("nonce").FirstOrDefault()); if (request.Headers.Contains("signature"))
signature = HttpUtility.UrlDecode(request.Headers.GetValues("signature").FirstOrDefault()); if (string.IsNullOrEmpty(timestamp) || string.IsNullOrEmpty(nonce) || string.IsNullOrEmpty(signature))
throw new SecurityException();

2、判断时间戳是否超过指定时间

   double ts = ;
bool timespanvalidate = double.TryParse(timestamp, out ts); bool falg = (DateTime.UtcNow - new DateTime(, , , , , , )).TotalMilliseconds - ts > * ; if (falg || (!timespanvalidate))
throw new SecurityException();

3、POST/DELETE/UPDATE 三种方式提取参数

  case "POST":
case "PUT":
case "DELETE": Stream stream = HttpContext.Current.Request.InputStream;
StreamReader streamReader = new StreamReader(stream);
sortedParams = new SortedDictionary<string, string>(new JsonSerializer().Deserialize<Dictionary<string, string>>(new JsonTextReader(streamReader))); break;

4、GET 方式提取参数

case "GET":

                    IDictionary<string, string> parameters = new Dictionary<string, string>();

                    foreach (string key in HttpContext.Current.Request.QueryString)
{
if (!string.IsNullOrEmpty(key))
{
parameters.Add(key, HttpContext.Current.Request.QueryString[key]);
}
} sortedParams = new SortedDictionary<string, string>(parameters); break;

5、排序上述参数并拼接,形成我们要参与md5的约定公式中的第四个参数

            StringBuilder query = new StringBuilder();

            if (sortedParams != null)
{
foreach (var sort in sortedParams.OrderBy(k => k.Key))
{
if (!string.IsNullOrEmpty(sort.Key))
{
query.Append(sort.Key).Append(sort.Value);
}
} data = query.ToString().Replace(" ", "");
}

6、开始约定公式计算结果并对比传过的结果是否一致

   var md5Staff = Seedwork.Utils.CharHelper.MD5(string.Concat(timestamp + nonce + staffId + data), );

            if (!md5Staff.Equals(signature))
throw new SecurityException();

完整的代码如下:

 public class ApiSecurityFilter : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
var request = actionContext.Request; var method = request.Method.Method;
var staffId = "^***********************************$"; string timestamp = string.Empty, nonce = string.Empty, signature = string.Empty; if (request.Headers.Contains("timestamp"))
timestamp = request.Headers.GetValues("timestamp").FirstOrDefault(); if (request.Headers.Contains("nonce"))
nonce = request.Headers.GetValues("nonce").FirstOrDefault(); if (request.Headers.Contains("signature"))
signature = request.Headers.GetValues("signature").FirstOrDefault(); if (string.IsNullOrEmpty(timestamp) || string.IsNullOrEmpty(nonce) || string.IsNullOrEmpty(signature))
throw new SecurityException(); double ts = ;
bool timespanvalidate = double.TryParse(timestamp, out ts); bool falg = (DateTime.UtcNow - new DateTime(, , , , , , )).TotalMilliseconds - ts > * ; if (falg || (!timespanvalidate))
throw new SecurityException("timeSpanValidate"); var data = string.Empty;
IDictionary<string, string> sortedParams = null; switch (method.ToUpper())
{
case "POST":
case "PUT":
case "DELETE": Stream stream = HttpContext.Current.Request.InputStream;
StreamReader streamReader = new StreamReader(stream);
sortedParams = new SortedDictionary<string, string>(new JsonSerializer().Deserialize<Dictionary<string, string>>(new JsonTextReader(streamReader))); break; case "GET": IDictionary<string, string> parameters = new Dictionary<string, string>(); foreach (string key in HttpContext.Current.Request.QueryString)
{
if (!string.IsNullOrEmpty(key))
{
parameters.Add(key, HttpContext.Current.Request.QueryString[key]);
}
} sortedParams = new SortedDictionary<string, string>(parameters); break; default:
throw new SecurityException("defaultOptions");
} StringBuilder query = new StringBuilder(); if (sortedParams != null)
{
foreach (var sort in sortedParams.OrderBy(k => k.Key))
{
if (!string.IsNullOrEmpty(sort.Key))
{
query.Append(sort.Key).Append(sort.Value);
}
} data = query.ToString().Replace(" ", "");
} var md5Staff = Seedwork.Utils.CharHelper.MD5(string.Concat(timestamp + nonce + staffId + data), ); if (!md5Staff.Equals(signature))
throw new SecurityException("md5Staff"); base.OnActionExecuting(actionContext);
} public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
base.OnActionExecuted(actionExecutedContext);
}
}

7、最后在asp.net mvc 里加入配置上述类

 public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
config.Filters.Add(new ApiSecurityFilter()); config.Filters.Add(new ApiHandleErrorAttribute()); // Web API routes
config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}

8、添加写入日志类(此类不是本文重点,详细参考 http://www.cnblogs.com/laogu2/p/5912153.html

  public class ApiHandleErrorAttribute: ExceptionFilterAttribute
{
/// <summary>
/// add by laiyunba
/// </summary>
/// <param name="filterContext">context oop</param>
public override void OnException(HttpActionExecutedContext filterContext)
{
LoggerFactory.CreateLog().LogError(Messages.error_unmanagederror, filterContext.Exception);
}
}

9、利用微信小程序测试接口

 var data = {
UserName: username,
Password: password,
Action: 'Mobile',
Sms: ''
}; var timestamp = util.gettimestamp();
var nonce = util.getnonce(); if (username && password) {
wx.request({
url: rootUrl + '/api/login',
method: "POST",
data: data,
header: {
'content-type': 'application/json',
'timestamp': timestamp,
'nonce': nonce,
'signature': util.getMD5Staff(data, timestamp, nonce)
},
success: function (res) {
if (res.data) {

1)其中getMD5Staff函数:
function getMD5Staff(queryData, timestamp, nonce) {

  var staffId = getstaffId();//保存的key与webapi同步
var data = dictionaryOrderWithData(queryData);
return md5.md5(timestamp + nonce + staffId + data);
}
2)dictionaryOrderWithData函数:
function dictionaryOrderWithData(dic) {
//eg {x:2,y:3,z:1}
var result = "";
var sdic = Object.keys(dic).sort(function (a, b) { return a.localeCompare(b) });
var value = ""; for (var ki in sdic) {
if (dic[sdic[ki]] == null) {
value = ""
}
else {
value = dic[sdic[ki]];
}
result += sdic[ki] + value;
} return result.replace(/\s/g, "");
}

10、测试日志

LaiyunbaApp Error: 2 : 2017-10-18 09:15:25    Unmanaged error in aplication, the exception information is Exception:System.Security.SecurityException: 安全性错误。
在 DistributedServices.MainBoundedContext.FilterAttribute.ApiSecurityFilter.OnActionExecuting(HttpActionContext actionContext)
在 System.Web.Http.Filters.ActionFilterAttribute.OnActionExecutingAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
--- 引发异常的上一位置中堆栈跟踪的末尾 ---
在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
在 System.Web.Http.Filters.ActionFilterAttribute.<ExecuteActionFilterAsyncCore>d__0.MoveNext()
--- 引发异常的上一位置中堆栈跟踪的末尾 ---
在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
在 System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__2.MoveNext()
--- 引发异常的上一位置中堆栈跟踪的末尾 ---
在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
在 System.Web.Http.Controllers.ExceptionFilterResult.<ExecuteAsync>d__0.MoveNext()
失败的程序集的区域是:
MyComputer
LogicalOperationStack=2017-10-18 09:15:25
2017-10-18 09:15:25 DateTime=2017-10-18T01:15:25.1000017Z
2017-10-18 09:15:25 Callstack= 在 System.Environment.GetStackTrace(Exception e, Boolean needFileInfo)
在 System.Environment.get_StackTrace()
在 System.Diagnostics.TraceEventCache.get_Callstack()
在 System.Diagnostics.TraceListener.WriteFooter(TraceEventCache eventCache)
在 System.Diagnostics.TraceSource.TraceEvent(TraceEventType eventType, Int32 id, String message)
在 Infrastructure.Crosscutting.NetFramework.Logging.TraceSourceLog.TraceInternal(TraceEventType eventType, String message)
在 Infrastructure.Crosscutting.NetFramework.Logging.TraceSourceLog.LogError(String message, Exception exception, Object[] args)
在 System.Web.Http.Filters.ExceptionFilterAttribute.OnExceptionAsync(HttpActionExecutedContext actionExecutedContext, CancellationToken cancellationToken)
在 System.Web.Http.Filters.ExceptionFilterAttribute.<ExecuteExceptionFilterAsyncCore>d__0.MoveNext()
在 System.Runtime.CompilerServices.AsyncTaskMethodBuilder.Start[TStateMachine](TStateMachine& stateMachine)
在 System.Web.Http.Filters.ExceptionFilterAttribute.ExecuteExceptionFilterAsyncCore(HttpActionExecutedContext actionExecutedContext, CancellationToken cancellationToken)
在 System.Web.Http.Filters.ExceptionFilterAttribute.System.Web.Http.Filters.IExceptionFilter.ExecuteExceptionFilterAsync(HttpActionExecutedContext actionExecutedContext, CancellationToken cancellationToken)
在 System.Web.Http.Controllers.ExceptionFilterResult.<ExecuteAsync>d__0.MoveNext()
在 System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.Start[TStateMachine](TStateMachine& stateMachine)
在 System.Web.Http.Controllers.ExceptionFilterResult.ExecuteAsync(CancellationToken cancellationToken)
在 System.Web.Http.ApiController.ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken)
在 System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()
在 System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.Start[TStateMachine](TStateMachine& stateMachine)
在 System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
在 System.Net.Http.HttpMessageInvoker.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
在 System.Web.Http.Dispatcher.HttpRoutingDispatcher.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)

至此,webapi加密工作已经全部完成,上述异常是直接访问url报的错误,必须在app环境下才可以正常访问。

 

总结:webapi加密机密很多,像微信小程序,用户很难拿到客户端app的源码,想知道我们的key也是无从说起。当然,我们也得定期更新app版本。

像app for andriod or ios 可以使用双向证书,或者使用我们上述的方式,然后加固app,防止不怀好意的人破解得到key,当然不管如何,我们首先要走的都是https协议!

作者:谷歌's谷歌's博客园
出处:http://www.cnblogs.com/laogu2/ 欢迎转载,但任何转载必须保留完整文章,在显要地方显示署名以及原文链接。如您有任何疑问或者授权方面的协商,请给我留言

asp.net mvc webapi 实用的接口加密方法的更多相关文章

  1. asp.net mvc webapi 实用的接口加密方法(转载)

    在很多项目中,因为webapi是对外开放的,这个时候,我们就要得考虑接口交换数据的安全性. 安全机制也比较多,如andriod与webapi 交换数据的时候,可以走双向证书方法,但是开发成本比较大, ...

  2. net mvc webapi 实用

    asp.net mvc webapi 实用的接口加密方法   在很多项目中,因为webapi是对外开放的,这个时候,我们就要得考虑接口交换数据的安全性. 安全机制也比较多,如andriod与webap ...

  3. .net异步性能测试(包括ASP.NET MVC WebAPI异步方法)

    很久没有写博客了,今年做的产品公司这两天刚刚开了发布会,稍微清闲下来,想想我们做的产品还有没有性能优化空间,于是想到了.Net的异步可以优化性能,但到底能够提升多大的比例呢?恰好有一个朋友正在做各种语 ...

  4. 案例:1 Ionic Framework+AngularJS+ASP.NET MVC WebApi Jsonp 移动开发

    落叶的庭院扫的一干二净之后,还要轻轻把树摇一下,抖落几片叶子,这才是Wabi Sabi的境界. 介绍:Ionic是移动框架,angularjs这就不用说了,ASP.Net MVC WebApi提供数据 ...

  5. ASP.NET MVC WebApi 返回数据类型序列化控制(json,xml) 用javascript在客户端删除某一个cookie键值对 input点击链接另一个页面,各种操作。 C# 往线程里传参数的方法总结 TCP/IP 协议 用C#+Selenium+ChromeDriver 生成我的咕咚跑步路线地图 (转)值得学习百度开源70+项目

    ASP.NET MVC WebApi 返回数据类型序列化控制(json,xml)   我们都知道在使用WebApi的时候Controller会自动将Action的返回值自动进行各种序列化处理(序列化为 ...

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

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

  7. 让Asp.net mvc WebAPI 支持OData协议进行分页查询操作

    这是我在用Asp.net mvc WebAPI 支持 OData协议 做分页查询服务时的 个人拙笔. 代码已经开发到oschina上.有兴趣的朋友可以看看,欢迎大家指出不足之处. 看过了园子里的几篇关 ...

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

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

  9. ASP.NET Core WebApi构建API接口服务实战演练

    一.ASP.NET Core WebApi课程介绍 人生苦短,我用.NET Core!提到Api接口,一般会想到以前用到的WebService和WCF服务,这三个技术都是用来创建服务接口,只不过Web ...

随机推荐

  1. css样式实现立方体制作

    <!doctype html> <html> <head> <meta charset="utf-8"> <title> ...

  2. 团队作业4——第一次项目冲刺(Alpha版本) 1

    一.Daily Scrum Meeting照片 二.燃尽图 三.项目进展 1.完页面的设计 采用gui页面,现在也是最初的页面设计 2.完成接口的定义 与组员共同定义了接口 四.困难与问题 此次主要利 ...

  3. win8下安装VC6出现兼容性问题的解决办法

    重装系统之后(win8的系统),发现VC6安装出现兼容性问题,花了一些时间解决,有出现的问题都差不多在下面链接的总结中,写的很详细: http://www.docin.com/p-1126120829 ...

  4. 学号:201521123116 《java程序设计》第八周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结集合与泛型相关内容. 1.2 选做:收集你认为有用的代码片段 List<Entry<String,Integer> ...

  5. 201521123068《Java程序设计》第4周学习总结

    1. 本周学习总结 1.1 尝试使用思维导图总结有关继承的知识点. 点击查看->高清脑图 1.2 使用常规方法总结其他上课内容. 答:学习继承与多态的知识,了解它们之间的关系:super.ext ...

  6. 201521123074 《Java程序设计》第3周学习总结

    1.本周学习总结 用百度脑图画了一张,点开图片全屏就可以看清楚了 脑图链接 2.书面作业 Q1.代码阅读 以下代码可否编译通过?哪里会出错?为什么?尝试改正? 如果创建3个Test1对象,有内存中有几 ...

  7. JAVA课设--五子棋--团队博客

    1 团队名称.团队成员介绍 徐璐琳 网络1511班 201521123010 祁泽文 网络1511班 201521123011 张晨晨 网络1511班 201521123009 2 项目git地址 团 ...

  8. 201521123038 《Java程序设计》 第十周学习总结

    201521123038 <Java程序设计> 第十周学习总结 1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结异常与多线程相关内容. 2. 书面作业 本次PTA作业题 ...

  9. 201521123115《java程序设计》第9周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结异常相关内容. 2. 书面作业 本次PTA作业题集异常 常用异常 题目5-1 1.1 截图你的提交结果(出现学号) 1.2 自己以前 ...

  10. SVN不出现绿色对勾的情况

    就目前而言,我出现了两种情况. Num1:电脑云盘可能不兼容,导致无法出现svn提示小icon:----->删除云盘重新启动. Num2:被设置覆盖.----->鼠标右键-->Tor ...