標籤:web 使用者資訊 原始碼 大致 方法 服務 linq cat can
在前一篇文章中,主要討論了使用HTTP基本認證的方法,因為HTTP基本認證的方式決定了它在安全性方面存在很大的問題,所以接下來看看另一種驗證的方式:digest authentication,即摘要認證。
系列文章列表
ASP.NET Web API(一):使用初探,GET和POST資料
ASP.NET Web API(二):安全驗證之使用HTTP基本認證
ASP.NET Web API(三):安全驗證之使用摘要認證(digest authentication)
摘要認證原理
在基本認證的方式中,主要的安全問題來自於使用者資訊的明文傳輸,而在摘要認證中,主要通過一些手段避免了此問題,大大增加了安全性。
為摘要驗證的驗證原理流程圖。
下面大致看一下這部分的驗證流程:
- 用戶端請求 /api/employees;
- 服務端返回401未驗證的狀態,並且在返回的資訊中包含了驗證方式Digest,realm的值,QOP(quality of protection)只設定成auth,nonce為一串隨機值,在下面的請求中會一直使用到,當過了存活期後服務端將重新整理產生一個新的nonce值;
- 用戶端接受到請求返回後,將username:realm:password進行HASH運算,假設運算後的值為HA1。又將請求的路徑/api/employees進行HASH運算,假設運算後的值為HA2。再將HA1:nonce:nc:cnonce:qop:HA2進行HASH運算,得到的值放在response中。這裡的cnonce為用戶端產生的nonce值,而nc用於統計,假設開始時為00000001,下次請求後就變成了00000002,不一定每次都加1,但是後面請求中的nc值肯定大於前一次請求中的nc值。
- 服務端收到請求後將驗證nonce是否到期,如果到期,那麼直接返回401,即第二步的狀態。如果沒有到期,那麼比較nc值,如果比前一次nc值小或者前一次根本沒有儲存的nc值,那麼也將直接返回401狀態。如果前面的驗證都通過,那麼服務端也將按照步驟3中計算最終HASH值的步驟計算出HASH值與用戶端的進行比較,然後比較用戶端提交過來的HASH值與服務端計算出來的HASH進行比較,不匹配返回401,匹配擷取請求的資料並返回狀態200。
摘要驗證主要就是通過上面的HASH比較的步驟避免掉了基本驗證中的安全性問題。
需要注意的是,如果需要IIS支援摘要驗證,需要把IIS摘要驗證的特性勾上。
摘要驗證的實現
在理解了摘要驗證的原理之後,只需要用代碼實現即可。
判斷nonce是否到期的方法。
1 public static bool IsValid(string nonce, string nonceCount) 2 { 3 Tuple<int, DateTime> cachedNonce = null; 4 nonces.TryGetValue(nonce, out cachedNonce); 5 6 if (cachedNonce != null) // nonce is found 7 { 8 // nonce count is greater than the one in record 9 if (Int32.Parse(nonceCount) > cachedNonce.Item1)10 {11 // nonce has not expired yet12 if (cachedNonce.Item2 > DateTime.Now)13 {14 // update the dictionary to reflect the nonce count just received in this request15 nonces[nonce] = new Tuple<int, DateTime>(Int32.Parse(nonceCount),16 cachedNonce.Item2);17 18 // Every thing looks ok - server nonce is fresh and nonce count seems to be 19 // incremented. Does not look like replay.20 return true;21 }22 }23 }24 25 return false;26 }判斷nonce是否到期的代碼
下面為摘要驗證實現的核心方法
1 namespace DigestAuthentication 2 { 3 public class AuthenticationHandler : DelegatingHandler 4 { 5 protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) 6 { 7 try 8 { 9 var headers = request.Headers;10 if (headers.Authorization != null)11 {12 Header header = new Header(request.Headers.Authorization.Parameter,13 request.Method.Method);14 15 if (Nonce.IsValid(header.Nonce, header.NounceCounter))16 {17 // Just assuming password is same as username for the purpose of illustration18 string password = header.UserName;19 20 string ha1 = String.Format("{0}:{1}:{2}", header.UserName, header.Realm,21 password).ToMD5Hash();22 23 string ha2 = String.Format("{0}:{1}", header.Method, header.Uri).ToMD5Hash();24 25 string computedResponse = String26 .Format("{0}:{1}:{2}:{3}:{4}:{5}",27 ha1, header.Nonce, header.NounceCounter,28 header.Cnonce, "auth", ha2).ToMD5Hash();29 30 if (String.CompareOrdinal(header.Response, computedResponse) == 0)31 {32 // digest computed matches the value sent by client in the response field.33 // Looks like an authentic client! Create a principal.34 var claims = new List<Claim>35 {36 new Claim(ClaimTypes.Name, header.UserName),37 new Claim(ClaimTypes.AuthenticationMethod, AuthenticationMethods.Password)38 };39 40 var principal = new ClaimsPrincipal(new[] { new ClaimsIdentity(claims, "Digest") });41 42 Thread.CurrentPrincipal = principal;43 44 if (HttpContext.Current != null)45 HttpContext.Current.User = principal;46 }47 }48 }49 50 var response = await base.SendAsync(request, cancellationToken);51 52 if (response.StatusCode == HttpStatusCode.Unauthorized)53 {54 response.Headers.WwwAuthenticate.Add(new AuthenticationHeaderValue("Digest",55 Header.UnauthorizedResponseHeader.ToString()));56 }57 58 return response;59 }60 catch (Exception)61 {62 var response = request.CreateResponse(HttpStatusCode.Unauthorized);63 response.Headers.WwwAuthenticate.Add(new AuthenticationHeaderValue("Digest",64 Header.UnauthorizedResponseHeader.ToString()));65 66 return response;67 }68 }69 }70 71 }摘要驗證實現的核心方法
實現完成後,使用摘要驗證只需要在對應的方法加上[Authorize]屬性標籤即可。
摘要驗證的優缺點
摘要驗證很好地解決了使用基本驗證所擔心的安全性問題。
但是永遠沒有絕對的安全,當使用者使用字典進行窮舉破解時,還是會存在一些被破解的隱患。
源碼下載
編輯器裡怎麼找不到上傳檔案的地方了?我上傳到了百度網盤裡。
原始碼下載
參考頁面:http://qingqingquege.cnblogs.com/p/5933752.html
ASP.NET Web API(三):安全驗證之使用摘要認證(digest authentication)