如何寫出安全的API接口(參數加密+超時處理+私鑰驗證+Https)- 續(附demo)

上篇文章說到接口安全的設計思路,若是沒有看到上篇博客,建議看完再來看這個。html

經過園友們的討論,以及我本身查了些資料,而後對接口安全作一個相對完善的總結,承諾給你們寫個demo,今天一併放出。git

對於安全也是相對的,下面我來根據安全級別分析github

 

1.徹底開放的接口web

有沒有這樣的接口,誰均可以調用,誰均可以訪問,不受時間空間限制,只要能連上互聯網就能調用,毫無安全可言。數據庫

實話說,這樣的接口咱們每天都在接觸,你查快遞,你查天氣預報,你查飛機,火車班次等,這些都是有公共的接口。api

我把這稱之爲裸奔時代。代碼以下:瀏覽器

/// <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); }
View Code

 

2.接口參數加密(基礎加密)安全

 你寫個接口,你只想讓特定的調用方使用,你把這些調用的人叫到一個小屋子,給他們宣佈說我這裏有個接口只打算給大家用,我給大家每人一把鑰匙,大家用的時候拿着這把鑰匙便可。app

這把鑰匙就是我上文說到的參數加密規則,有了這個規則就能調用。ide

這有安全問題啊,這裏面的某個成員若是哪一個不當心丟了鑰匙或者被人竊取,掌握鑰匙的人是否是也能夠來掉用接口了呢?並且他能夠複製不少鑰匙給不明不白的人用。

至關於有人拿到了你的請求連接,若是業務沒有對連接惟一性作判斷(實際上業務邏輯一般不會把每次請求的加密簽名記錄下來,因此不會作惟一性判斷),就會被重複調用,有必定安全漏洞,怎麼破?先看這個場景的代碼,而後繼續往下看!

/// <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); }
View Code

 

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); }
View Code

 

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); }
View Code

 

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中的各個調用接口方法來實現接口調用。

一、若是想驗證參數錯誤,須要在請求接口時打個斷點把接口url取出,篡改url參數,而後在瀏覽器中模擬請求

二、若是想驗證接口超時,須要在請求接口時打個斷點把接口url取出,而後等到了超時時間,而後在瀏覽器中模擬請求

三、若是想驗證私鑰錯誤,須要在請求接口時打個斷點把接口url取出,而後修改business的私鑰配置,而後在瀏覽器中模擬請求

相關文章
相關標籤/搜索