上篇文章说到接口安全的设计思路,如果没有看到上篇博客,建议看完再来看这个。

通过园友们的讨论,以及我自己查了些资料,然后对接口安全做一个相对完善的总结,承诺给大家写个demo,今天一并放出。

对于安全也是相对的,下面我来根据安全级别分析

1.完全开放的接口

有没有这样的接口,谁都可以调用,谁都可以访问,不受时间空间限制,只要能连上互联网就能调用,毫无安全可言。

实话说,这样的接口我们天天都在接触,你查快递,你查天气预报,你查飞机,火车班次等,这些都是有公共的接口。

我把这称之为裸奔时代。代码如下:

  1. /// <summary>
  2. /// 接口对外公开
  3. /// </summary>
  4. /// <returns></returns>
  5. [HttpGet]
  6. [Route("NoSecure")]
  7. public HttpResponseMessage NoSecure(int age)
  8. {
  9. var result = new ResultModel<object>()
  10. {
  11. ReturnCode = ,
  12. Message = string.Empty,
  13. Result = string.Empty
  14. };
  15.  
  16. var dataResult = stulist.Where(T => T.Age == age).ToList();
  17. result.Result = dataResult;
  18.  
  19. return GetHttpResponseMessage(result);
  20. }

2.接口参数加密(基础加密)

你写个接口,你只想让特定的调用方使用,你把这些调用的人叫到一个小屋子,给他们宣布说我这里有个接口只打算给你们用,我给你们每人一把钥匙,你们用的时候拿着这把钥匙即可。

这把钥匙就是我上文说到的参数加密规则,有了这个规则就能调用。

这有安全问题啊,这里面的某个成员如果哪个不小心丢了钥匙或者被人窃取,掌握钥匙的人是不是也可以来掉用接口了呢?而且他可以复制很多钥匙给不明不白的人用。

相当于有人拿到了你的请求链接,如果业务没有对链接唯一性做判断(实际上业务逻辑通常不会把每次请求的加密签名记录下来,所以不会做唯一性判断),就会被重复调用,有一定安全漏洞,怎么破?先看这个场景的代码,然后继续往下看!

  1. /// <summary>
  2. /// 接口加密
  3. /// </summary>
  4. /// <returns></returns>
  5. [HttpGet]
  6. [Route("SecureBySign")]
  7. public HttpResponseMessage SecureBySign([FromUri]int age, long _timestamp, string appKey, string _sign)
  8. {
  9. var result = new ResultModel<object>()
  10. {
  11. ReturnCode = ,
  12. Message = string.Empty,
  13. Result = string.Empty
  14. };
  15.  
  16. #region 校验签名是否合法
  17. var param = new SortedDictionary<string, string>(new AsciiComparer());
  18. param.Add("age", age.ToString());
  19. param.Add("appKey", appKey);
  20. param.Add("_timestamp", _timestamp.ToString());
  21.  
  22. string currentSign = SignHelper.GetSign(param, appKey);
  23.  
  24. if (_sign != currentSign)
  25. {
  26. result.ReturnCode = -;
  27. result.Message = "签名不合法";
  28. return GetHttpResponseMessage(result);
  29. }
  30. #endregion
  31.  
  32. var dataResult = stulist.Where(T => T.Age == age).ToList();
  33. result.Result = dataResult;
  34.  
  35. return GetHttpResponseMessage(result);
  36. }

3.接口参数加密+接口时效性验证(一般达到这个级别已经非常安全了)

继上一步,你发现有不明不白的人调用你的接口,你很不爽,随即把真正需要调用接口的人又叫来,告诉他们每天给他们换一把钥匙。和往常一样,有个别伙伴的钥匙被小偷偷走了,小偷煞费苦心,经过数天的踩点观察,准备在一个月黑风高的夜晚动手。拿出钥匙,捣鼓了半天也无法开启你的神圣之门,因为小偷不知道你天天都在换新钥匙。

小偷不服,经过一段时间琢磨,小偷发现了你们换钥匙的规律。在一次获得钥匙之后,不加思索,当天就动手了,因为他知道他手里的钥匙在第二天你更换钥匙后就失效了。

结果,小偷如愿。怎么破?先看这个场景的代码,然后继续往下看!

  1. /// <summary>
  2. /// 接口加密并根据时间戳判断有效性
  3. /// </summary>
  4. /// <returns></returns>
  5. [HttpGet]
  6. [Route("SecureBySign/Expired")]
  7. public HttpResponseMessage SecureBySign_Expired([FromUri]int age, long _timestamp, string appKey, string _sign)
  8. {
  9. var result = new ResultModel<object>()
  10. {
  11. ReturnCode = ,
  12. Message = string.Empty,
  13. Result = string.Empty
  14. };
  15.  
  16. #region 判断请求是否过期---假设过期时间是20秒
  17. DateTime requestTime = GetDateTimeByTicks(_timestamp);
  18.  
  19. if (requestTime.AddSeconds() < DateTime.Now)
  20. {
  21. result.ReturnCode = -;
  22. result.Message = "接口过期";
  23. return GetHttpResponseMessage(result);
  24. }
  25. #endregion
  26.  
  27. #region 校验签名是否合法
  28. var param = new SortedDictionary<string, string>(new AsciiComparer());
  29. param.Add("age", age.ToString());
  30. param.Add("appKey", appKey);
  31. param.Add("_timestamp", _timestamp.ToString());
  32.  
  33. string currentSign = SignHelper.GetSign(param, appKey);
  34.  
  35. if (_sign != currentSign)
  36. {
  37. result.ReturnCode = -;
  38. result.Message = "签名不合法";
  39. return GetHttpResponseMessage(result);
  40. }
  41. #endregion
  42.  
  43. var dataResult = stulist.Where(T => T.Age == age).ToList();
  44. result.Result = dataResult;
  45.  
  46. return GetHttpResponseMessage(result);
  47. }

4.接口参数加密+时效性验证+私钥(达到这个级别安全性固若金汤)

继上一步,你发现道高一尺魔高一丈,仍然有偷盗事情发生。咋办呢?你打算下血本,给每个人配一把钥匙的基础上,再给每个人发个暗号,即使钥匙被小偷弄去了,小偷没有暗号,任然无法如愿。即使小偷真正的如愿,这样也很容易定位是谁的暗号泄漏问题,找到问题根源,只需要给当前这个人换下钥匙就行了,不用大动干戈。

但这个并不是万无一失的,因为钥匙和暗号毕竟还有可能被小偷搞到。代码如下:

  1. /// <summary>
  2. /// 接口加密并根据时间戳判断有效性而且带着私有key校验
  3. /// </summary>
  4. /// <returns></returns>
  5. [HttpGet]
  6. [Route("SecureBySign/Expired/KeySecret")]
  7. public HttpResponseMessage SecureBySign_Expired_KeySecret([FromUri]int age, long _timestamp, string appKey, string _sign)
  8. {
  9. //key集合,这里随便弄两个测试数据
  10. //如果调用方比较多,需要审核授权,根据一定的规则生成key把这些数据存放在数据库中,如果功能扩展开来,可以针对不同的调用方做不同的功能权限管理
  11. //在调用接口时动态从库里取,每个调用方在调用时带上他的key,调用方一般把自己的key放到网站配置中
  12. Dictionary<string, string> keySecretDic = new Dictionary<string, string>();
  13. keySecretDic.Add("key_zhangsan", "D9U7YY5D7FF2748AED89E90HJ88881E6");//张三的key,
  14. keySecretDic.Add("key_lisi", "I9O6ZZ3D7FF2748AED89E90ZB7732M9");//李四的key
  15.  
  16. var result = new ResultModel<object>()
  17. {
  18. ReturnCode = ,
  19. Message = string.Empty,
  20. Result = string.Empty
  21. };
  22.  
  23. #region 判断请求是否过期---假设过期时间是20秒
  24. DateTime requestTime = GetDateTimeByTicks(_timestamp);
  25.  
  26. if (requestTime.AddSeconds() < DateTime.Now)
  27. {
  28. result.ReturnCode = -;
  29. result.Message = "接口过期";
  30. return GetHttpResponseMessage(result);
  31. }
  32. #endregion
  33.  
  34. #region 根据appkey获取key值
  35. string secret = keySecretDic.Where(T => T.Key == appKey).FirstOrDefault().Value;
  36. #endregion
  37.  
  38. #region 校验签名是否合法
  39. var param = new SortedDictionary<string, string>(new AsciiComparer());
  40. param.Add("age", age.ToString());
  41. param.Add("appKey", appKey);
  42.  
  43. param.Add("appSecret", secret);//把secret加入进行加密
  44.  
  45. param.Add("_timestamp", _timestamp.ToString());
  46.  
  47. string currentSign = SignHelper.GetSign(param, appKey);
  48.  
  49. if (_sign != currentSign)
  50. {
  51. result.ReturnCode = -;
  52. result.Message = "签名不合法";
  53. return GetHttpResponseMessage(result);
  54. }
  55. #endregion
  56.  
  57. var dataResult = stulist.Where(T => T.Age == age).ToList();
  58. result.Result = dataResult;
  59.  
  60. return GetHttpResponseMessage(result);
  61. }

5.接口参数加密+时效性验证+私钥+Https(我把这个级别称之为金钟罩,世间最安全莫过于此)

继上一步,我们给传输机制改为Https,这下小偷彻底懵逼了。那么问题来了,Https咋玩儿呢?可以在本地搭个环境,参考此文:http://www.cnblogs.com/naniannayue/archive/2012/11/19/2776948.html

另:本文的接口是用的MVC WebAPI写的,完全基于RESTful标准。如对此不是特别了解可以参考此文:http://www.cnblogs.com/landeanfen/p/5501490.html

完整demo下载

注:demo不能直接运行,需要把两个web项目配置到iis中,api代表接口提供方,他的主域需要配置到business的webconfig中,在浏览器地址栏分别请求business中的各个调用接口方法来实现接口调用。

1、如果想验证参数错误,需要在请求接口时打个断点把接口url取出,篡改url参数,然后在浏览器中模拟请求

2、如果想验证接口超时,需要在请求接口时打个断点把接口url取出,然后等到了超时时间,然后在浏览器中模拟请求

3、如果想验证私钥错误,需要在请求接口时打个断点把接口url取出,然后修改business的私钥配置,然后在浏览器中模拟请求

如何写出安全的API接口(参数加密+超时处理+私钥验证+Https)- 续(附demo)的更多相关文章

  1. 如何写出安全的API接口

    通过园友们的讨论,以及我自己查了些资料,然后对接口安全做一个相对完善的总结,承诺给大家写个demo,今天一并放出. 对于安全也是相对的,下面我来根据安全级别分析 1.完全开放的接口 有没有这样的接口, ...

  2. 如何写出安全的API接口?接口参数加密签名设计思路

    开发中经常用到接口,尤其是在面向服务的soa架构中,数据交互全是用的接口. 几年以前我认为,我写个接口,不向任何人告知我的接口地址,我的接口就是安全的,现在回想真是too young,too simp ...

  3. 如何写出安全的 API 接口?接口参数加密签名设计思路

    原文链接:http://blog.csdn.net/ma_jiang/article/details/53636840

  4. .NET API 接口数据传输加密最佳实践

    .NET API 接口数据传输加密最佳实践 我们在做 Api 接口时,相信一定会有接触到要给传输的请求 body 的内容进行加密传输.其目的就是为了防止一些敏感的内容直接被 UI 层查看或篡改. 其实 ...

  5. api接口参数问题

    对于取数据,我们使用最多的应该就是get请求了吧.下面通过几个示例看看我们的get请求参数传递. 回到顶部 1.基础类型参数 [HttpGet] public string GetAllChargin ...

  6. 写出Hibernate中核心接口/类的名称,并描述他们各自的责任?

    Hibernate的核心接口一共有5个,分别为:Session.SessionFactory.Transaction.Query和 Configuration.这5个核心接口在任何开发中都会用到.通过 ...

  7. 开放api接口参数 app_id, app_key, app_secret 的理解

    看到知乎上一个回答很形象: app_id, app_key, app_secret:我的身份证,银行卡号,银行卡密码 (完)

  8. 【定有惊喜】android程序员如何做自己的API接口?php与android的良好交互(附环境搭建),让前端数据动起来~

    一.写在前面 web开发有前端和后端之分,其实android还是有前端和后端之分.android开发就相当于手机app的前端,一般都是php+android或者jsp+android开发.androi ...

  9. Spring 接口参数加密传输

    加密方式 AES spring jar 包 pom.xml配置(注意版本)         <dependency>             <groupId>org.spri ...

随机推荐

  1. ResponsibleChain(责任链模式)

    /** * 责任链模式 * @author TMAC-J * 老板讲任务交给CTO,CTO自然不会亲自去做,又把人物分配给项目经理,项目经理再把任务分配给组长,组长再分配给个人 * 如果中途哪个环节出 ...

  2. SQL 提示介绍 hash/merge/concat union

    查询提示一直是个很有争议的东西,因为他影响了sql server 自己选择执行计划.很多人在问是否应该使用查询提示的时候一般会被告知慎用或不要使用...但是个人认为善用提示在不修改语句的条件下,是常用 ...

  3. windows 部署 git 服务器报 Please make sure you have the correct access rights and the repository exists.错误

    这两天在阿里云上弄windows 服务器,顺便部署了一个git服务.根据网上教程一步步操作下来,最后在 remote远程仓库的时候提示 fatal: 'yourpath/test.git' does ...

  4. Linux+apache+mono+asp.net安装教程

    Linux+apache+mono+asp.net安装教程(CentOS上测试的) 一.准备工作: 1.安装linux系统(CentOS,这个就不多讲了) 2.下载所需软件 http-2.4.4.ta ...

  5. AngularJS 第三天----作用域

    作用域的概念及其功能 AngularJS使用作用域的概念来充当数据模型的作用,在视图和控制器之间起着桥梁的作用.由于双向绑定的数据特性,视图的修改会更新 $scope,同样对 $scope的修改也会重 ...

  6. 虚拟机体验之 KVM 篇

    在上一篇中,我展示了虚拟机软件 QEMU 的使用.效果及其性能,同时也分析了不同用户对虚拟机的不同追求.但是不管是桌面用户还是企业级用户,对虚拟机软件的追求有一点是共同的,那就是性能.QEMU 是一个 ...

  7. .NET 基础一步步一幕幕[面向对象前言]

    面向对象前言 2017年的第一篇博文,好久不写博文了,赶紧补上,感觉在以前的<.NET 基础一步步一幕幕>系列博客中,简短的小知识点已经介绍的差不多的(PS:如果还有别的基础知识点我没有介 ...

  8. 搭建LNAMP环境(一)- 源码安装MySQL5.6

    1.yum安装编译mysql需要的包 yum -y install gcc-c++ make cmake bison-devel ncurses-devel perl 2.为mysql创建一个新的用户 ...

  9. .Net中的RealProxy实现AOP

    序言 这个AOP要从我们公司的一个事故说起,前段时间公司的系统突然在乌云中出现,数据被泄露的一览无余,乌云上显示是SQL注入攻击.呵,多么贴近生活的一个露洞,可谓是人尽皆知啊.然而却华丽丽的给拉我们一 ...

  10. JavaScript的同步与异步

    1.手绘一张图说明. 2.为什么JavaScript是单线程(这里引用阮一峰老师的话) JavaScript的单线程,与它的用途有关. 作为浏览器脚本语言,JavaScript的主要用途是与用户互动, ...