如何使用簽名保證ASP.NET MVC OR WEBAPI的接口安全
當(dāng)我們開(kāi)發(fā)一款A(yù)pp的時(shí)候,App需要跟后臺(tái)服務(wù)進(jìn)行通信獲取或者提交數(shù)據(jù)。如果我們沒(méi)有完善的安全機(jī)制則很容易被別用心的人偽造請(qǐng)求而篡改數(shù)據(jù)。
所以我們需要使用某種安全機(jī)制來(lái)保證請(qǐng)求的合法?,F(xiàn)在最常用的辦法是給每個(gè)http請(qǐng)求添加一個(gè)簽名,服務(wù)端來(lái)驗(yàn)證簽名的合法性,如果簽名合法則執(zhí)行響應(yīng)的操作,如果簽名非法則直接拒絕請(qǐng)求。
簽名算法
簽名算法一般都使用Hash散列算法,常用的有MD5,SHA系列算法。這些算法可以根據(jù)不同的輸入,計(jì)算出不同的結(jié)果,而且碰撞的概率很低。
簽名算法跟加密算法不是一回事。很多同學(xué)都會(huì)說(shuō)使用MD5加密一下,其實(shí)這是錯(cuò)誤的。簽名算法不能恢復(fù)原來(lái)的數(shù)據(jù),因?yàn)樗旧聿⒉话瓉?lái)數(shù)據(jù)的信息。
而加密方法不同,加密方法是可以根據(jù)加密結(jié)果重新推算出原來(lái)的數(shù)據(jù)的。
HMAC SHA作為一種更加安全的簽名算法,使用一個(gè)Key來(lái)影響簽名的結(jié)果。這樣同樣的輸入配合不同的Key可以得出不同的簽名,更加安全。
public static string HmacSHA256(string secretKey,string plain) { var keyBytes = Encoding.UTF8.GetBytes(secretKey); var plainBytes = Encoding.UTF8.GetBytes(plain); using (var hmacsha256 = new HMACSHA256(keyBytes)) { var sb = new StringBuilder(); var hashValue = hmacsha256.ComputeHash(plainBytes); foreach (byte x in hashValue) { sb.Append(String.Format("{0:x2}", x)); } return sb.ToString(); } }
簽名的參數(shù)
有了簽名算法,那么我們簽名的內(nèi)容哪里來(lái)呢?
一般我們使用http請(qǐng)求的queryString然后加上時(shí)間戳還有隨機(jī)數(shù)來(lái)作為簽名的參數(shù)。
public static string MakeSignPlain(SortedDictionary<string,string> queryString,string time,string random ) { var sb = new StringBuilder(); foreach (var keyValue in queryString) { sb.AppendFormat("{0}={1}&", keyValue.Key, keyValue.Value); } if (sb.Length>1) { sb.Remove(sb.Length - 1, 1); } sb.Append(time); sb.Append(random); return sb.ToString().ToUpper(); }
驗(yàn)證簽名
驗(yàn)證簽名就是簡(jiǎn)單的比較服務(wù)端生產(chǎn)的簽名跟客戶端生產(chǎn)的簽名是否一直。
要注意的一點(diǎn)是最好驗(yàn)證下時(shí)間戳,跟服務(wù)端時(shí)間比較前后不能相差5分鐘。這也是一個(gè)簡(jiǎn)單的防Replay Attack的手段。
public static bool Valid(string requestSign,string signPlain,string time, string secretKey) { if (string.IsNullOrEmpty(time)||string.IsNullOrEmpty(requestSign)||string.IsNullOrEmpty(signPlain)) { return false; } //is in range var now = DateTime.Now; long requestTime =0; if (long.TryParse(time,out requestTime)) { var max = now.AddMinutes(5).ToString("yyyyMMddHHmmss"); var min = now.AddMinutes(-5).ToString("yyyyMMddHHmmss"); if (!(long.Parse(max) >= requestTime && long.Parse(min) <= requestTime)) { return false; } } else { return false; } //hashmac var sign = Encryption.HmacSHA256(secretKey, signPlain); return requestSign.Equals(sign, StringComparison.CurrentCultureIgnoreCase); }
ApiController基類
有了上面這些鋪墊我們就可以在基類完成簽名的驗(yàn)證了??蛻舳诵枰焉厦嫣岬降臅r(shí)間戳,隨機(jī)數(shù),簽名和客戶端的ID放入http請(qǐng)求的headers里面。
我們?cè)诨惖腛nActionExecuting里取出這些數(shù)據(jù)組合成簽名的參數(shù),然后根據(jù)客戶端ID獲取簽名的Key,然后使用同樣的簽名算法計(jì)算簽名。并且比較客戶端的簽名跟服務(wù)端的簽名是否一致。
這里就不演示了。
預(yù)防Replay Attack
預(yù)防重放攻擊主要有兩點(diǎn):
- 校驗(yàn)時(shí)間戳的范圍
時(shí)間戳跟服務(wù)器時(shí)間相差在一個(gè)合理的范圍內(nèi)視為合法。
- 緩存簽名
每次請(qǐng)求都去判斷下簽名是否出現(xiàn)過(guò)。如果出現(xiàn)過(guò)則視為非法請(qǐng)求。
因?yàn)橛袝r(shí)間戳跟隨機(jī)數(shù)的存在,所以理論上每次請(qǐng)求的簽名是不可能重復(fù)的。
客戶端調(diào)用
這里演示一下C#簽名并且調(diào)用http接口的代碼
[TestMethod()] public void GetUserTest() { string url = "http://localhost:8090/api/test/GetUser"; string userId = "A39891D4-6CEF-4538-A562-3A422CA9C17A"; string appId = "100001"; string secretKey = "M/vkPOWXgBa7GnRd73t7j+jsKfbZtb+f"; string rumdon = Guid.NewGuid().ToString(); string time = DateTime.Now.ToString("yyyyMMddHHmmss"); //make signture plain text var sortDict = new SortedDictionary<string, string>() { {"userId",userId } }; var signPlain = new StringBuilder(); foreach (var keyValue in sortDict) { signPlain.AppendFormat("{0}={1}&", keyValue.Key, keyValue.Value); } if (signPlain.Length > 1) { //remove last & signPlain.Remove(signPlain.Length - 1, 1); } signPlain.Append(time); signPlain.Append(random); Console.WriteLine("sign plain:{0}", signPlain.ToString().ToUpper()); //make sign var sign = Encryption.HmacSHA256(secretKey, signPlain.ToString().ToUpper()); Console.WriteLine("sign:{0}", sign); string requestUrl = string.Format("{0}?{1}={2}", url, "userId", userId); HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestUrl); request.Method = "GET"; //add headers request.Headers.Add("time", time); request.Headers.Add("appId", appId); request.Headers.Add("random", random); request.Headers.Add("sign", sign); // //start request try { using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) { var responseStream = response.GetResponseStream(); if (responseStream != null) { using (StreamReader reader = new StreamReader(responseStream)) { var content = reader.ReadToEnd(); Console.WriteLine(content); } } } } catch (WebException ex) { using (HttpWebResponse response = (HttpWebResponse)ex.Response) { var responseStream = response.GetResponseStream(); if (responseStream != null) { using (StreamReader reader = new StreamReader(responseStream)) { var content = reader.ReadToEnd(); Console.WriteLine(content); } } } } }
以上就是如何使用簽名保證ASP.NET MVC OR WEBAPI的接口安全的詳細(xì)內(nèi)容,更多關(guān)于用簽名保證ASP.NET MVC OR WEBAPI的接口安全的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
.net 動(dòng)態(tài)標(biāo)題實(shí)現(xiàn)方法
.net 實(shí)現(xiàn)動(dòng)態(tài)標(biāo)題方法,需要的朋友可以參考下。2009-11-11記一次EFCore類型轉(zhuǎn)換錯(cuò)誤及解決方案
這篇文章主要介紹了記一次EFCore類型轉(zhuǎn)換錯(cuò)誤及解決方案,幫助大家更好的理解和學(xué)習(xí)使用asp.net core,感興趣的朋友可以了解下2021-03-03登錄時(shí)記住用戶名和密碼及cookie案例應(yīng)用
本文將實(shí)現(xiàn)登錄時(shí)記住用戶的帳號(hào)密碼,接下來(lái)我們來(lái)模擬一個(gè)登錄介面,要把這個(gè)登錄的信息記錄至Cookie,還要把Cookie的過(guò)期時(shí)間設(shè)置7天之后過(guò)期,感興趣的朋友可以參考下,希望本文對(duì)你的cookie學(xué)習(xí)有所幫助2013-01-01Asp.Mvc?2.0實(shí)現(xiàn)用戶注冊(cè)實(shí)例講解(1)
這篇文章主要介紹了Asp.Mvc?2.0如何實(shí)現(xiàn)用戶注冊(cè),實(shí)例講解很細(xì)致,注冊(cè)功能是每個(gè)網(wǎng)站必不可少的組成部分,感興趣的的朋友可以參考下2015-08-08CorFlags.exe檢查.NET程序平臺(tái)目標(biāo)(Platform Target)的工具
.NET Framework SDK中的一個(gè)工具程序: CorFlags.exe。CorFlags.exe不但可查詢.NET組件的平臺(tái)目標(biāo)設(shè)定,甚至能直接修改設(shè)定,省去重新編譯的工夫。2013-02-02asp.net 網(wǎng)頁(yè)編碼自動(dòng)識(shí)別代碼
另外一位網(wǎng)友空間/IV提供的代碼,功能同HttpWebRequest獲取網(wǎng)頁(yè)源代碼時(shí)自動(dòng)識(shí)別網(wǎng)頁(yè)編碼2008-09-09實(shí)例講解動(dòng)態(tài)加載gridview中的行及其樣式
加載gridview中的行及其樣式想必大家都知道,那么如何動(dòng)態(tài)加載呢?下面有個(gè)不錯(cuò)的示例,感興趣的朋友可以參考下2013-10-10ASP.NET MVC小結(jié)之基礎(chǔ)篇(二)
本文續(xù)上篇文章,還是介紹些asp.net mvc相關(guān)的基礎(chǔ)知識(shí),非常的詳細(xì),新手朋友們看看,高手們略過(guò)吧2014-11-11