ASP.NET Web API(三):安全验证之使用摘要认证(digest authentication)

前一篇文章中,主要讨论了使用HTTP基本认证的方法,因为HTTP基本认证的方式决定了它在安全性方面存在很大的问题,所以接下来看看另一种验证的方式:digest authentication,即摘要认证。

系列文章列表

ASP.NET Web API(一):使用初探,GET和POST数据
ASP.NET Web API(二):安全验证之使用HTTP基本认证
ASP.NET Web API(三):安全验证之使用摘要认证(digest authentication)

摘要认证原理

在基本认证的方式中,主要的安全问题来自于用户信息的明文传输,而在摘要认证中,主要通过一些手段避免了此问题,大大增加了安全性。

下图为摘要验证的验证原理流程图。

下面大致看一下这部分的验证流程:

  1. 客户端请求 /api/employees;
  2. 服务端返回401未验证的状态,并且在返回的信息中包含了验证方式Digest,realm的值,QOP(quality of protection)只设置成auth,nonce为一串随机值,在下面的请求中会一直使用到,当过了存活期后服务端将刷新生成一个新的nonce值;
  3. 客户端接受到请求返回后,将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值。
  4. 服务端收到请求后将验证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 yet
12                     if (cachedNonce.Item2 > DateTime.Now)
13                     {
14                         // update the dictionary to reflect the nonce count just received in this request
15                         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 illustration
18                         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 = String
26                                       .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

时间: 2024-10-02 10:10:50

ASP.NET Web API(三):安全验证之使用摘要认证(digest authentication)的相关文章

asp.net权限认证:摘要认证(digest authentication)

asp.net权限认证系列 asp.net权限认证:Forms认证 asp.net权限认证:HTTP基本认证(http basic) asp.net权限认证:Windows认证 asp.net权限认证:摘要认证(digest authentication) 一.摘要认证由来 摘要认证是对基本认证的改进,即是用摘要代替账户密码,从而防止明文传输中账户密码的泄露 之前对摘要认证也不是很熟悉,还得感谢圆中的 parry 贡献的博文:ASP.NET Web API(三):安全验证之使用摘要认证(dige

[转]asp.net权限认证:摘要认证(digest authentication)

本文转自:http://www.cnblogs.com/lanxiaoke/p/6357501.html 摘要认证简单介绍 摘要认证是对基本认证的改进,即是用摘要代替账户密码,从而防止明文传输中账户密码的泄露 之前对摘要认证也不是很熟悉,还得感谢圆中的 parry 贡献的博文:ASP.NET Web API(三):安全验证之使用摘要认证(digest authentication) 我是觉得真心不错,让我少走很多弯路.这篇文章主要是对上边引用文章的讲解,老司机可以略过. 老规矩,上摘认证的工作流

ASP.NET Web API之FluentValidation验证

最近在做Web API,用到了流式验证,就简单的说说这个流式验证. 首先我们定义一个Filter,如下  public class ValidateResponseFilterAttribute : ActionFilterAttribute     {         public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext)         {     

ASP.NET Web API模型验证以及异常处理方式

ASP.NET Web API的模型验证与ASP.NET MVC一样,都使用System.ComponentModel.DataAnnotations. 具体来说,比如有:[Required(ErrorMessage="")][Range(0, 999)][Bind(Exclude="")][DisplayName("")][StringLength(1024)]... 验证扩展可以看这里:http://dataannotationsextens

【ASP.NET Web API教程】4.3 ASP.NET Web API中的异常处理

参考页面: http://www.yuanjiaocheng.net/webapi/create-crud-api-1-delete.html http://www.yuanjiaocheng.net/webapi/Consume-web-api.html http://www.yuanjiaocheng.net/webapi/mvc-consume-webapi-get.html http://www.yuanjiaocheng.net/webapi/mvc-consume-webapi-po

购物车Demo,前端使用AngularJS,后端使用ASP.NET Web API(3)--Idetity,OWIN前后端验证

原文:购物车Demo,前端使用AngularJS,后端使用ASP.NET Web API(3)--Idetity,OWIN前后端验证 chsakell分享了前端使用AngularJS,后端使用ASP.NET Web API的购物车案例,非常精彩,这里这里记录下对此项目的理解. 文章:http://chsakell.com/2015/01/31/angularjs-feat-web-api/http://chsakell.com/2015/03/07/angularjs-feat-web-api-

ASP.NET Web API 2基于令牌的身份验证

基于令牌的认证 我们知道WEB网站的身份验证一般通过session或者cookie完成的,登录成功后客户端发送的任何请求都带上cookie,服务端根据客户端发送来的cookie来识别用户. WEB API使用这样的方法不是很适合,于是就有了基于令牌的认证,使用令牌认证有几个好处:可扩展性.松散耦合.移动终端调用比较简单等等,别人都用上了,你还有理由不用吗? 下面我们花个20分钟的时间来实现一个简单的WEB API token认证: Step 1: 新建一个空的WEB API项目,项目名称就设置为

ASP.NET Web API(二):安全验证之使用HTTP基本认证

在前一篇文章ASP.NET Web API(一):使用初探,GET和POST数据中,我们初步接触了微软的REST API: Web API. 我们在接触了Web API的后就立马发现了有安全验证的需求,所以这篇文章我们先来讨论下安全验证一个最简单的方法:使用HTTP基本认证. HTTP基本认证原理 在HTTP协议进行通信的过程中,HTTP协议定义了基本认证过程以允许HTTP服务器对WEB浏览器进行用户身份认证的方法,当一个客户端向HTTP服务器进行数据请求时,如果客户端未被认证,则HTTP服务器

Asp.Net Web API 2第三课——.NET客户端调用Web API

Asp.Net Web API 导航 Asp.Net Web API第一课——入门http://www.cnblogs.com/aehyok/p/3432158.html Asp.Net Web API第二课——CRUD操作http://www.cnblogs.com/aehyok/p/3434578.html 前言 本教程演示从一个控制台应用程序,使用HttpClient调用Web API.我们也将使用上一个教程中建立的Web API.你可以直接在http://www.cnblogs.com/