如何写出安全的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下载

 

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

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

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

http://www.cnblogs.com/accumulater/p/6178166.html


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/272526.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux系统文件编程(1)

打开文件 int open(const char *pathname, int flags); int open(const char *pathname, int flags, mode_t mode);open----返回的是文件描述符是整形数&#xff08;文件描述符在形式上是一个非负整数。实际上&#xff0c;它是一个索引值&#xff0c;指向内核为每一个进程所维…

【收集】常用的cmd命令

运行操作CMD命令&#xff1a;开始&#xff0d;>运行&#xff0d;>键入cmd或command(在命令行里可以看到系统版本、文件系统版本)CMD命令锦集1. gpedit.msc-----组策略2. sndrec32-------录音机3. Nslookup-------IP地址侦测器 &#xff0c;是一个 监测网络中 DNS 服务器是…

MVC框架详解--Servlet+JSP+JavaBean模式(MVC)开发复杂的web应用

孤傲苍狼 javaweb学习总结(二十二)——基于ServletJSPJavaBean开发模式的用户登录注册 转载于:https://www.cnblogs.com/yangjj08/p/10153657.html

Linux文件编程(2)

文件打开创建补充 &#xff08;1&#xff09;O_EXCL O_EXCL和O_CREAT配合使用 若文件不存在则创建文件 若文件存在则返回-1 代码演示 #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include<stdio.h> int main() {int fd;fdope…

IT技术人员必须思考的几个问题

1.搞IT的是屌丝、码农、程序猿?人们提到IT人的时候&#xff0c;总会想到他们呆板、不解风情&#xff0c;专注于IT技术&#xff0c;就算性感的美女躺在旁边也无动于衷。事实真的是这样吗?虽说不能完全否定有这样的情况存在&#xff0c;但这是IT人普遍的特点吗?而其它行业也有…

37个JavaScript基本面试问题和解答

https://www.zcfy.cc/article/37-essential-javascript-interview-questions-and-answers1、使用typeof bar “object”来确定bar是否是一个对象时有什么潜在的缺陷&#xff1f;这个陷阱如何避免&#xff1f;尽管typeof bar “object”是检查bar是否是对象的可靠方法&#xff0…

封装cookie.js、EventUtil.js、

最近学习了javascript&#xff0c;封装好的东西看起来舒服&#xff0c;以备需要的时候拉出来&#xff0c;jquery对javascript做了很好的封装&#xff01;以后会多用jquery多些var CookieUtil {get: function (name){var cookieName encodeURIComponent(name) "",c…

实现linux cp 命令和修改配置文件

cp指令用来代码的拷贝 以下由文件编程代码实现 代码演示 #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include<stdio.h> #include <unistd.h> #include <string.h>#include <stdlib.h> int main(int argc…

最实用前端开发框架对比评测

现在&#xff0c;各种开发框架层出不穷&#xff0c;但是&#xff0c;真正的精品却为数不多。今天我们根据Github上的流行程度整理了2014年最受欢迎的5个前端开发框架&#xff0c;并进行对比说明&#xff0c;希望帮助有需要的朋友选择合适自己的前端框架。1. BootstrapBootstrap…

HBase1.0.0 实现数据增删查

HBase1.0.0 即Hadoop 2.6 采用maven 的方式实现HBase数据简单操作 import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Random;import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.Path; import org.a…

linux 写结构体到文件

将整数写入到文件 #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include<stdio.h> #include <unistd.h> #include <string.h>#include <stdlib.h> int main() {int fd;int data100;int data20;fdopen("…

程序员常访问的国外技术交流网站

技术人员经常会在各种技术交流社区游逛&#xff0c;大家互相学习、交流、分享、帮助。互联网拉近了地球人的距离&#xff0c;让全世界的技术人员可以聚集在一起分享交流。当然因为多方面原因&#xff0c;通常最新最权威的技术知识传到国内存在一定“时差”。本文将给大家分享技…

标准C库对文件操作的引入

modeopen和fopen的区别 fopen、fread、fwrite的使用 &#xff08;1&#xff09;fopen FILE *fopen(const char *path, const char *mode);path&#xff1a;文件路径 mode&#xff1a;以什么权限打开&#xff0c;要用双引号 它的返回值并不是文件描述符 若失败返回NULL 若操作成…

转载爱哥自定义View系列--Paint详解

上图是paint中的各种set方法 这些属性大多我们都可以见名知意&#xff0c;很好理解&#xff0c;即便如此&#xff0c;哥还是带大家过一遍逐个剖析其用法&#xff0c;其中会不定穿插各种绘图类比如Canvas、Xfermode、ColorFilter等等的用法。 set(Paint src) 顾名思义为当前画笔…

只有程序员才懂这些黑色幽默!

也是机缘巧合&#xff0c;让我一个之前工作从未接触过程序员的人&#xff0c;现在成天和程序员打交道&#xff0c;要知道&#xff0c;不懂技术&#xff0c;往往他们想和你幽默的搞笑一下&#xff0c;未必能读懂。都说程序员情商低&#xff0c;不爱说话&#xff0c;比较闷骚。可…

tiny4412 linux+qtopia nfs网络文件系统的挂载

1,首先确定uboot启动内核的bootargs参数 Linux-CommandLine root/dev/nfs nfsroot192.168.1.131:/home/tiny4412/rootfs_qtopia_qt4 ip192.168.1.230:192.168.1.131:192.168.1.1:255.255.255.0::eth0:off rootfstypenfs consolettySAC0,115200 init/linuxrc ctp2 skipcaliy uh…

Linux 进程、父进程、子进程

进程和程序的区别 一、 进程是动态的&#xff0c;程序是静态的&#xff1a;程序是有序代码的集合&#xff0c;进程是程序的执行。进程有核心态/用户态。 二、 进程是暂时的&#xff0c;程序是永久的&#xff1b;进程是一个状态变化的过程&#xff0c;程序可以长久保存 三、进…

几款开源富文本编辑器优缺点比较

1、百度UEditor 优点&#xff1a;插件多&#xff0c;基本满足各种需求&#xff0c;类似贴吧中的回复界面。缺点&#xff1a;不再维护&#xff0c;文档极少&#xff0c;使用并不普遍&#xff0c;图片只能上传到本地服务器&#xff0c;如果需要上传到其他服务器需要改动源码&…

C程序的储存空间是如何分配?

可执行程序包括BSS段、数据段、代码段。 在类UNIX系统下可使用size命令查看可执行文件的段大小信息。如size a.out&#xff1a; ~/Desktop/MyC$ size a.outtext data bss dec hex filename1672 600 8 2280 8e8 a.out1.数据段存放已初始化的全…

详细讲解Android的网络通信(HttpUrlConnection和HttpClient)

前言&#xff0c;Android的网络通信的方式有两种&#xff1a;使用Socket或者HTTP&#xff0c;今天这一篇我们详细讲解使用HTTP实现的网络通信&#xff0c;HTTP又包括两种方式编程方式&#xff1a; &#xff08;1&#xff09;HttpUrlConnection&#xff1b; &#xff08;2&#…