如何写出安全的API接口
通过园友们的讨论,以及我自己查了些资料,然后对接口安全做一个相对完善的总结,承诺给大家写个demo,今天一并放出。
对于安全也是相对的,下面我来根据安全级别分析
1.完全开放的接口
有没有这样的接口,谁都可以调用,谁都可以访问,不受时间空间限制,只要能连上互联网就能调用,毫无安全可言。
实话说,这样的接口我们天天都在接触,你查快递,你查天气预报,你查飞机,火车班次等,这些都是有公共的接口。
我把这称之为裸奔时代。代码如下:
/// <summary>
/// 接口对外公开
/// </summary>
/// <returns></returns>
[HttpGet]
[Route("NoSecure")]
public HttpResponseMessage NoSecure(int age)
{
var result = new ResultModel<object>()
{
ReturnCode = 0,
Message = string.Empty,
Result = string.Empty
};
var dataResult = stulist.Where(T => T.Age == age).ToList();
result.Result = dataResult;
return GetHttpResponseMessage(result);
}
2.接口参数加密(基础加密)
你写个接口,你只想让特定的调用方使用,你把这些调用的人叫到一个小屋子,给他们宣布说我这里有个接口只打算给你们用,我给你们每人一把钥匙,你们用的时候拿着这把钥匙即可。
这把钥匙就是我上文说到的参数加密规则,有了这个规则就能调用。
这有安全问题啊,这里面的某个成员如果哪个不小心丢了钥匙或者被人窃取,掌握钥匙的人是不是也可以来掉用接口了呢?而且他可以复制很多钥匙给不明不白的人用。
相当于有人拿到了你的请求链接,如果业务没有对链接唯一性做判断(实际上业务逻辑通常不会把每次请求的加密签名记录下来,所以不会做唯一性判断),就会被重复调用,有一定安全漏洞,怎么破?先看这个场景的代码,然后继续往下看!
/// <summary>
/// 接口加密
/// </summary>
/// <returns></returns>
[HttpGet]
[Route("SecureBySign")]
public HttpResponseMessage SecureBySign([FromUri]int age, long _timestamp, string appKey, string _sign)
{
var result = new ResultModel<object>()
{
ReturnCode = 0,
Message = string.Empty,
Result = string.Empty
};
#region 校验签名是否合法
var param = new SortedDictionary<string, string>(new AsciiComparer());
param.Add("age", age.ToString());
param.Add("appKey", appKey);
param.Add("_timestamp", _timestamp.ToString());
string currentSign = SignHelper.GetSign(param, appKey);
if (_sign != currentSign)
{
result.ReturnCode = -2;
result.Message = "签名不合法";
return GetHttpResponseMessage(result);
}
#endregion
var dataResult = stulist.Where(T => T.Age == age).ToList();
result.Result = dataResult;
return GetHttpResponseMessage(result);
}
3.接口参数加密+接口时效性验证(一般达到这个级别已经非常安全了)
继上一步,你发现有不明不白的人调用你的接口,你很不爽,随即把真正需要调用接口的人又叫来,告诉他们每天给他们换一把钥匙。和往常一样,有个别伙伴的钥匙被小偷偷走了,小偷煞费苦心,经过数天的踩点观察,准备在一个月黑风高的夜晚动手。拿出钥匙,捣鼓了半天也无法开启你的神圣之门,因为小偷不知道你天天都在换新钥匙。
小偷不服,经过一段时间琢磨,小偷发现了你们换钥匙的规律。在一次获得钥匙之后,不加思索,当天就动手了,因为他知道他手里的钥匙在第二天你更换钥匙后就失效了。
结果,小偷如愿。怎么破?先看这个场景的代码,然后继续往下看!
/// <summary>
/// 接口加密并根据时间戳判断有效性
/// </summary>
/// <returns></returns>
[HttpGet]
[Route("SecureBySign/Expired")]
public HttpResponseMessage SecureBySign_Expired([FromUri]int age, long _timestamp, string appKey, string _sign)
{
var result = new ResultModel<object>()
{
ReturnCode = 0,
Message = string.Empty,
Result = string.Empty
};
#region 判断请求是否过期---假设过期时间是20秒
DateTime requestTime = GetDateTimeByTicks(_timestamp);
if (requestTime.AddSeconds(20) < DateTime.Now)
{
result.ReturnCode = -1;
result.Message = "接口过期";
return GetHttpResponseMessage(result);
}
#endregion
#region 校验签名是否合法
var param = new SortedDictionary<string, string>(new AsciiComparer());
param.Add("age", age.ToString());
param.Add("appKey", appKey);
param.Add("_timestamp", _timestamp.ToString());
string currentSign = SignHelper.GetSign(param, appKey);
if (_sign != currentSign)
{
result.ReturnCode = -2;
result.Message = "签名不合法";
return GetHttpResponseMessage(result);
}
#endregion
var dataResult = stulist.Where(T => T.Age == age).ToList();
result.Result = dataResult;
return GetHttpResponseMessage(result);
}
4.接口参数加密+时效性验证+私钥(达到这个级别安全性固若金汤)
继上一步,你发现道高一尺魔高一丈,仍然有偷盗事情发生。咋办呢?你打算下血本,给每个人配一把钥匙的基础上,再给每个人发个暗号,即使钥匙被小偷弄去了,小偷没有暗号,任然无法如愿,而且这样很容易定位是谁的暗号泄漏问题,找到问题根源,只需要给当前这个人换下钥匙就行了,不用大动干戈。
但这个并不是万无一失的,因为钥匙毕竟还有可能被小偷搞到。代码如下:
/// <summary>
/// 接口加密并根据时间戳判断有效性而且带着私有key校验
/// </summary>
/// <returns></returns>
[HttpGet]
[Route("SecureBySign/Expired/KeySecret")]
public HttpResponseMessage SecureBySign_Expired_KeySecret([FromUri]int age, long _timestamp, string appKey, string _sign)
{
//key集合,这里随便弄两个测试数据
//如果调用方比较多,需要审核授权,根据一定的规则生成key把这些数据存放在数据库中,如果功能扩展开来,可以针对不同的调用方做不同的功能权限管理
//在调用接口时动态从库里取,每个调用方在调用时带上他的key,调用方一般把自己的key放到网站配置中
Dictionary<string, string> keySecretDic = new Dictionary<string, string>();
keySecretDic.Add("key_zhangsan", "D9U7YY5D7FF2748AED89E90HJ88881E6");//张三的key,
keySecretDic.Add("key_lisi", "I9O6ZZ3D7FF2748AED89E90ZB7732M9");//李四的key
var result = new ResultModel<object>()
{
ReturnCode = 0,
Message = string.Empty,
Result = string.Empty
};
#region 判断请求是否过期---假设过期时间是20秒
DateTime requestTime = GetDateTimeByTicks(_timestamp);
if (requestTime.AddSeconds(20) < DateTime.Now)
{
result.ReturnCode = -1;
result.Message = "接口过期";
return GetHttpResponseMessage(result);
}
#endregion
#region 根据appkey获取key值
string secret = keySecretDic.Where(T => T.Key == appKey).FirstOrDefault().Value;
#endregion
#region 校验签名是否合法
var param = new SortedDictionary<string, string>(new AsciiComparer());
param.Add("age", age.ToString());
param.Add("appKey", appKey);
param.Add("appSecret", secret);//把secret加入进行加密
param.Add("_timestamp", _timestamp.ToString());
string currentSign = SignHelper.GetSign(param, appKey);
if (_sign != currentSign)
{
result.ReturnCode = -2;
result.Message = "签名不合法";
return GetHttpResponseMessage(result);
}
#endregion
var dataResult = stulist.Where(T => T.Age == age).ToList();
result.Result = dataResult;
return GetHttpResponseMessage(result);
}
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不能直接运行,需要把两个web项目配置到iis中,api代表接口提供方,他的主域需要配置到business的webconfig中,在浏览器地址栏分别请求business中的各个调用接口方法来实现接口调用。
1、如果想验证接口超时,需要在请求接口时打个断点把接口url取出,然后等到了超时时间,然后在浏览器中模拟请求
2、如果想验证参数错误,需要在请求接口时打个断点把接口url取出,篡改url参数,然后在浏览器中模拟请求
如何写出安全的API接口的更多相关文章
- 如何写出安全的API接口(参数加密+超时处理+私钥验证+Https)- 续(附demo)
上篇文章说到接口安全的设计思路,如果没有看到上篇博客,建议看完再来看这个. 通过园友们的讨论,以及我自己查了些资料,然后对接口安全做一个相对完善的总结,承诺给大家写个demo,今天一并放出. 对于安全 ...
- 如何写出安全的API接口?接口参数加密签名设计思路
开发中经常用到接口,尤其是在面向服务的soa架构中,数据交互全是用的接口. 几年以前我认为,我写个接口,不向任何人告知我的接口地址,我的接口就是安全的,现在回想真是too young,too simp ...
- 如何写出安全的 API 接口?接口参数加密签名设计思路
原文链接:http://blog.csdn.net/ma_jiang/article/details/53636840
- 写出Hibernate中核心接口/类的名称,并描述他们各自的责任?
Hibernate的核心接口一共有5个,分别为:Session.SessionFactory.Transaction.Query和 Configuration.这5个核心接口在任何开发中都会用到.通过 ...
- 怎样提供一个好的移动API接口服务/从零到一[开发篇]
引语:现在互联网那么热,你手里没几个APP都不好意思跟别人打招呼!但是,难道APP就是全能的神吗?答案是否定的,除了优雅的APP前端展示,其实核心还是服务器端.数据的保存.查询.消息的推送,无不是在服 ...
- 程序员不得不知道的 API 接口常识
说实话,我非常希望两年前刚准备找实习的自己能看到本篇文章,那个时候懵懵懂懂,跟着网上的免费教程做了一个购物商城就屁颠屁颠往简历上写. 至今我仍清晰地记得,那个电商教程是怎么定义接口的: 管它是增加.修 ...
- 使用json-server搭建模拟api接口
转载:http://blog.csdn.net/adojayfan/article/details/55011674 作为前端和客户端开发人员,在后端还没有给出对应的api接口时,我们无法做测试. 这 ...
- Django使用AJAX调用自己写的API接口
Django使用AJAX调用自己写的API接口 *** 具体代码和数据已上传到github https://github.com/PythonerKK/eleme-api-by-django-rest ...
- 写api接口神器--带你5分钟了解swagger
随着互联网技术的发展,现在的网站架构基本都由原来的后端渲染,变成了:前端渲染.先后端分离的形态,而且前端技术和后端技术在各自的道路上越走越远. 前端和后端的唯一联系,变成了API接口:API文档变成了 ...
随机推荐
- linux查看内核版本、系统版本、系统位数(32or64)
linux查看内核版本.系统版本.系统位数(32or64) 2011-05-01 22:05:12 标签:linux 内核版本 休闲 系统版本 系统位数 1. 查看内核版本命令: 1) [root@ ...
- 测试Swift语言代码高亮-使用highlight.js
func &( left:OCBool, right: OCBool)->OCBool{ if left{ return right } else{ return false } }
- 自动化测试工具Selenium和QTP的比较
一.用户仿真:Selenium在浏览器后台执行,它通过修改HTML的DOM(文档对象模型)来执行操作,实际上是通过javascript来控制的.执行时窗口可以最小化,可以在同一机器执行多个测试.QTP ...
- C语言内存对齐详解(1)
一.什么是字节对齐,为什么要对齐? 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特定的内存地址访问,这 ...
- 如何在Linux命令行中创建以及展示演示稿
导读 你在准备一场演讲的时候,脑海可能会先被图文并茂.形象华丽的演示图稿所占据.诚然,没有人会否认一份生动形象的演讲稿所带来的积极作用.然而,并非所有的演讲都需要TED Talk的质量.更多时候,演讲 ...
- 经典sql语句
经典SQL语句大全 一.基础 1.说明:创建数据库CREATE DATABASE database-name 2.说明:删除数据库drop database dbname3.说明:备份sql serv ...
- cocos2d::Vector
C++中的vector使用范例 一.概述 vector是C++标准模板库中的部分内容,它是一个多功能的,能够操作多种数据结构和算法的模板类和函数库.vector是一个容器,它能够存放各种类型的对象,简 ...
- 右移>> 和 左移<<
一个int占四个字节,也就是32位,这样的话1不论左移还是右移32位仍旧移到原来的位置,就仍旧是1了. 右移是除,左移是乘.1除1除32次和1乘1乘32次当然都还是1了. 移位操作的简单计算方法 &g ...
- Unique Binary Search Trees I & II
Given n, how many structurally unique BSTs (binary search trees) that store values 1...n? Example Gi ...
- sharepoint部件webparth关闭找回的方法