如何使用簽名保證ASP.NET MVC OR WEBAPI的介面安全
當我們開發一款App的時候,App需要跟後臺服務進行通訊獲取或者提交資料。如果我們沒有完善的安全機制則很容易被別用心的人偽造請求而篡改資料。
所以我們需要使用某種安全機制來保證請求的合法。現在最常用的辦法是給每個http請求新增一個簽名,服務端來驗證簽名的合法性,如果簽名合法則執行響應的操作,如果簽名非法則直接拒絕請求。
簽名演算法
簽名演算法一般都使用Hash雜湊演算法,常用的有MD5,SHA系列演算法。這些演算法可以根據不同的輸入,計算出不同的結果,而且碰撞的概率很低。
簽名演算法跟加密演算法不是一回事。很多同學都會說使用MD5加密一下,其實這是錯誤的。簽名演算法不能恢復原來的資料,因為它本身並不包含原來數
而加密方法不同,加密方法是可以根據加密結果重新推算出原來的資料的。
HMAC SHA作為一種更加安全的簽名演算法,使用一個Key來影響簽名的結果。這樣同樣的輸入配合不同的Key可以得出不同的簽名,更加安全。
public static string HmacSHA256(string secretKey,string plain) { http://www.cppcns.com var keyBytes = Encoding.UTF8.GetBytes(secretKey); var plainBytes = E程式設計客棧ncoding.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(); } }
簽名的引數
有了簽名演算法,那麼我們簽名的內容哪裡來呢?
一般我們使用http請求的queryString然後加上時間戳還有隨機數來作為簽名的引數。
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(); }
驗證簽名
驗證簽名就是簡單的比較服務端生產的簽名跟客戶端生產的簽名是否一直。
要注意的一點是最好驗證下時間戳,跟服務端時間比較前後不能相差5分鐘。這也是一個簡單的防Replay Attack的手段。
public static bool Valid(string requestSign,string signPlain,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))
{
http://www.cppcns.com return false;
}
}
else
{
return false;
}
//hashmac
var sign = Encryption.HmacSHA256(secretKey,signPlain);
return requestSign.Equals(sign,StringComparison.CurrentCultureIgnoreCase);
}
ApiController基類
有了上面這些鋪墊我們就可以在基類完成簽名的驗證了。客戶端需要把上面提到的時間戳,隨機數,簽名和客戶端的ID放入http請求的headers裡面。
我們在基類的OnActionExecuting裡取出這些資料組合成簽名的引數,然後根據客戶端ID獲取簽名的Key,然後使用同樣的簽名演算法計算簽名。並且比較客戶端的簽名跟服務端的簽名是否一致。
這裡就不演示了。
預防Replay Attack
預防重放攻擊主要有兩點:
- 校驗時間戳的範圍
時間戳跟伺服器時間相差在一個合理的範圍內視為合法。
- 快取簽名
每次請求都去判斷下簽名是否出現過。如果出現過則視為非法請求。
因為有時間戳跟隨機數的存在,所以理論上每次請求的簽名是不可能重複的。
客戶端呼叫
這裡演示一下C#簽名並且呼叫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.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 (HttpWebReshttp://www.cppcns.componse 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的介面安全的詳細內容,更多關於用簽名保證ASP.NET MVC OR WEBAPI的介面安全的資料請關注我們其它相關文章!