如何写安全性的接口

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
时间: 2024-10-14 05:33:33

如何写安全性的接口的相关文章

(原创)多系统间需要对接,我写了一个接口框架。实用性非常强,写出来大家交流。需要的可以直接搬过去用。(第1篇)

业务是这样:有个手机app,在ios或者android上开发的,他需要访问服务器数据.我在服务器上,做了一个接口,专门开放一些数据给app去用. 我写的接口优势:我写的这个接口,全部是面向对象结构,代码简单而非常好用,极易扩展.可读性很强,容错性高. 个人建议有需要的同学可以直接拿去用到项目中..我会一步步讲他的制作方法. 第1步,创建一个工程,在工程中,创建一个网站,以及一个业务操作类库.如下图: 上图是网站. 上图是类库 第2步,创建几个根类.cs文件.如上图,创建:Post.cs文件:用于

NTP精准授时核心板定制设计 安全性好 接口丰富 授时容量大

NTP精准授时核心板定制设计 安全性好 接口丰富 授时容量大 NTP精准授时核心板是我公司自主研发设计,总结和归纳了以前产品的优缺点和用户体验后优化完善的产品.已广泛应用于电力自动化,通信基站,应急通信,数字广电,轨道交通,航空航天,金融自动化领域等需要精密时钟服务的场所. 一.授时核心板模块功能特点: 1.支持IEE1588-2008协议. 2.授时精度可达ns级,背靠背授时精度优于50ns. 3.支持组播和单播传输模式. 4.支持MASTER.SLAVE模式可灵活配置,2个10/100/10

PC端写的API接口和手机端APP联合调试

一.遇到问题的情况:项目框架:asp.net MVC5 ,写的给手机端调用的API接口. 二.自己在本地 IIS上部署项目,在手机端的请求服务器上把地址和端口换上本地部署的,如图所示 三.用管理员的身份打开VS,打开项目.找到调试-->附加到进程 找到部署项目运行对应的进程,选择后添加添加. 然后你的程序也就 进入调试模式,从APP上调用接口,就可以进入到PC端的调试模式,看看传参对不对,PC端代码逻辑等bug调试. 原文地址:https://www.cnblogs.com/ElvisZhong

如何写一个webService接口

第一次写接口的时候,感觉太过笼统,压根不知道接口是个什么东东,,后来自己也查了好多资料,才发现其实接口可以就认为是一个方法,自己多写几种以后就会发现挺简单的,自己整理了一下资料,纯属增强自己的记忆,也方便更多像我这样的菜鸟们参考... 下面是我自己写的一个案例,用来同步文件用的这里我用的流,也可以用mutipartfile: 1.调用接口方法: package com.weichai.test; import org.apache.cxf.endpoint.Client;import org.a

通过flask框架写成http接口调用Ansible

#*******一.flask_ansible.py文件 #!/usr/bin/env python #_*_ coding:utf-8 _*_ import json from flask import Flask,request from ansible_api_job import Ansibles app = Flask(__name__) @app.route('/ansible/command', methods=['GET','POST']) def command():     

手写实现List接口的ArrayList类

接口  MyLlist.java 1 package cn.ftf.myarraylist; 2 3 public interface MyList { 4 public void clear(); 5 public boolean isEmpty(); 6 public int length(); 7 public Object get(int i) throws Exception; 8 public void add(Object obj); 9 public void inset(int

为什么自动注入写的是接口名

来自某程序员一个问答问题: 1. 有一点没明白,为什么注解@repository注解的是接口UserDAO的实现类UserDAOImpl,而在UserServiceImpl中使用@Autowired注解注入属性private UserDAO  userDAO自动装配,为什么最后得到的是UserDAOImpl的实例. -----上面是某位同学的提问,我也有这样的疑问---- 2. @Service注解服务层的时候,在unitest中,是从ApplicationContext.getBean("实现

使用PHP写一个简易接口

安装XAMPP和Coda,创建本地服务器>>http://localhost/index.html 左为XAMPP(Apache服务器,MySQL数据库,PHP) 右为Coda 在Coda中创建登录界面(Get 和 Post)和Get,Post接受请求界面: 1 <!-- login.php --> 2 3 <html > 4 <head > 5 <meta charset="utf-8"/> 6 <title >

用java给php写个万能接口

package helloworld; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServ