如何写出安全的API接口(参数加密+超时处理+私钥验证+Https)

摘要:
我把这称之为裸奔时代。这把钥匙就是我上文说到的参数加密规则,有了这个规则就能调用。=currentSign){result.ReturnCode=-2;result.Message="签名不合法";returnGetHttpResponseMessage;}#endregionvardataResult=stulist.Where.ToList();result.Result=dataResult;returnGetHttpResponseMessage;}3.接口参数加密+接口时效性验证继上一步,你发现有不明不白的人调用你的接口,你很不爽,随即把真正需要调用接口的人又叫来,告诉他们每天给他们换一把钥匙。结果,小偷如愿。//////接口加密并根据时间戳判断有效性//////[HttpGet][Route]publicHttpResponseMessageSecureBySign_Expired{varresult=newResultModel(){ReturnCode=0,Message=string.Empty,Result=string.Empty};#region判断请求是否过期---假设过期时间是20秒DateTimerequestTime=GetDateTimeByTicks;if{result.ReturnCode=-1;result.Message="接口过期";returnGetHttpResponseMessage;}#endregion#region校验签名是否合法varparam=newSortedDictionary;param.Add;param.Add;param.Add;stringcurrentSign=SignHelper.GetSign;if(_sign!

原文:http://www.cnblogs.com/codeon/p/6123863.html#3580351

1.完全开放的接口

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

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

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

/// <summary>
        /// 接口对外公开
        /// </summary>
        /// <returns></returns>
[HttpGet]
        [Route("NoSecure")]
        public HttpResponseMessage NoSecure(intage)
        {
            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;
            returnGetHttpResponseMessage(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>(newAsciiComparer());
            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 = "签名不合法";
                returnGetHttpResponseMessage(result);
            }
            #endregion
            var dataResult = stulist.Where(T => T.Age ==age).ToList();
            result.Result =dataResult;
            returnGetHttpResponseMessage(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 = "接口过期";
                returnGetHttpResponseMessage(result);
            }
            #endregion
            #region 校验签名是否合法
            var param = new SortedDictionary<string, string>(newAsciiComparer());
            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 = "签名不合法";
                returnGetHttpResponseMessage(result);
            }
            #endregion
            var dataResult = stulist.Where(T => T.Age ==age).ToList();
            result.Result =dataResult;
            returnGetHttpResponseMessage(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 = "接口过期";
                returnGetHttpResponseMessage(result);
            }
            #endregion
            #region 根据appkey获取key值
            string secret = keySecretDic.Where(T => T.Key ==appKey).FirstOrDefault().Value;
            #endregion
            #region 校验签名是否合法
            var param = new SortedDictionary<string, string>(newAsciiComparer());
            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 = "签名不合法";
                returnGetHttpResponseMessage(result);
            }
            #endregion
            var dataResult = stulist.Where(T => T.Age ==age).ToList();
            result.Result =dataResult;
            returnGetHttpResponseMessage(result);
        }

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

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

免责声明:文章转载自《如何写出安全的API接口(参数加密+超时处理+私钥验证+Https)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇使用对称加密来加密Spring Cloud Config配置文件Linux与Windows共享资源samba+mount下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

WebApi使用Token(OAUTH 2.0方式)

1.在项目中添加引用 Microsoft.AspNet.WebApi.Owin Microsoft.Owin.Host.SystemWeb Microsoft.Owin.Security.OAuth Microsoft.Owin.Security.Cookies Microsoft.AspNet.Identity.Owin Microsoft.Owin.C...

Kafka长文总结

Kafka是目前使用较多的消息队列,以高吞吐量得到广泛使用 特点: 1、同时为发布和订阅提供搞吞吐量。Kafka的设计目标是以时间复杂度为O(1)的方式提供消息持久化能力的,即使对TB级别以上数据也能保证常数时间的访问性能,即使在非常廉价的商用机器上也能做到单机支持每秒100K条消息的传输(一般消息处理是百万级,使用Partition实现机器间的并行处理)...

Unicode基本概念

Unicode是计算机可以支持这个星球上多种语言的秘密武器。通过使用一个或者多个字节来表示一个字符的方法突破了ASCII的限制。Unicode可以表示超过90000个字符。 使用方式:a=u'hello' #Unicode String String的内建函数str()和chr()并没有升级来处理Unicode,新的内建函数unicode()和unichar...

接口上传base64编码图片

1 package com.*.util; 2 3 import java.io.FileInputStream; 4 5 6 import java.io.FileOutputStream; 7 import java.io.IOException; 8 import java.io.InputStream; 9 import j...

Go 每日一库之 flag

缘起 我一直在想,有什么方式可以让人比较轻易地保持每日学习,持续输出的状态。写博客是一种方式,但不是每天都有想写的,值得写的东西。有时候一个技术比较复杂,写博客的时候经常会写着写着发现自己的理解有偏差,或者细节还没有完全掌握,要去查资料,了解了之后又继续写,如此反复。这样会导致一篇博客的耗时过长。 我在每天浏览思否、掘金和Github的过程中,发现一些比较...

(2)OLEDB数据库操作

1、首先要引入 System.Data.OracleClient.dll 2、引入命名空间using System.Data.OleDb; OleDb类https://msdn.microsoft.com/zh-cn/library/system.data.oledb(v=vs.110).aspx 一、连接数据库 连接字符串 string str = "...