摘要认证及实现HTTP digest authentication

最近工作需要做了摘要认证(digest authentication),下面就工作中遇到的问题及过程做一个总结。

  1. 第一次客户端请求
    GET/POST

  2. 服务器产生一个随机数nonce,服务器将这个随机数放在WWW-Authenticate响应头,与服务器支持的认证算法列表,认证的域realm一起发送给客户端,如下例子:
    HTTP /1.1 401 Unauthorized
    WWW-Authenticate:Digest
    realm= ”test realm”
    qop=auth,auth-int”
    nonce=”66C4EF58DA7CB956BD04233FBB64E0A4”
    opaque=“5ccc069c403ebaf9f0171e9517f40e41”

    •	realm的值是一个简单的字符串
    •	qop是认证的(校验)方式
    •	nonce是随机数, 可以用GUID
    •	opaque是个随机字符串,它只是透传而已,即客户端还会原样返回过来。
    •	algorithm 是个字符串,用来指示用来产生分类及校验和的算法对。如果该域没指定,则认为是“MD5“算法。
    
  3. 客户端发现是401响应,表示需要进行认证,则弹出让用户输入用户名和密码的认证窗口,客户端选择一个算法,计算出密码和其他数据的摘要(response),将摘要放到Authorization的请求头中发送给服务器,如果客户端要对服务器也进行认证,这个时候,可以发送客户端随机数cnonce。如下例子:

     GET/cgi-bin/checkout?a=b HTTP/1.1
     Authorization: Digest
     username="Mufasa", 
     realm="realm", 
     nonce="dcd98b7102dd2f0e8b11d0f600bfb0c0",  uri="/xxxx/System/Register",  
     qop=auth,  nc=00000001,  cnonce="0a4f113b",
     response="6629fae49393a05397450978507c4ef1",  
     opaque="5ccc069c403ebaf9f0171e9517f40e41"
    
  4. 服务接受摘要,选择算法,获取数据库用户名密码,重新计算新的摘要跟客户端传输的摘要进行比较,验证是否匹配。
    200 OK

  5. MD5计算方式
    在这里插入图片描述

//解析客户端发送过来的请求报头中的Authorization
Stringauthorization=request.getHeader("Authorization");
//其参数不为空,利用参数值,和服务器上存储的口令,进行比对。
if(authorization!=null&&!"".equals(authorization)){
。。。
 
Stringusername=map.get("username");
Stringrealm=map.get("realm");
Stringpassword=userService.getPassword(username);
Stringmethod=request.getMethod();
Stringuri=map.get("uri");
Stringnonce=map.get("nonce");
Stringnc=map.get("nc");
Stringcnonce=map.get("cnonce");
Stringqop=map.get("qop");
//客户端传过来的摘要
StringresponseFromClient=map.get("response");
 
//MD5计算
Stringa1=username+":"+realm+":"+password;
Stringha1=MD5Utils.getMD5(a1);
 
Stringa2=method+":"+uri;
Stringha2=MD5Utils.getMD5(a2);
//服务器计算出的摘要
StringresponseBefore=ha1+":"+nonce+":"+nc+":"+cnonce+":"+qop+":"+ha2;
StringresponseMD5=MD5Utils.getMD5(responseBefore);
//两者摘要相同,即验证成功
if(responseMD5!=null&&responseMD5.equals(responseFromClient)){
业务逻辑。。。
//两者摘要不相同,验证失败
}else{
业务逻辑。。。
}
//其参数为空,返回参数到客户端,并发起质询。
}else{
//拼接AuthorizationHeader,格式如Digestusername="admin",realm="Restrictedarea",nonce="554a3304805fe",qop=auth,opaque="cdce8a5c95a1427d74df7acbf41c9ce0",nc=00000001,response="391bee80324349ea1be02552608c0b10",cnonce="0a4f113b",uri="/MyBlog/home/Response/response_last_modified"
StringBuildersb=newStringBuilder();
sb.append("Digest");
sb.append("realm").append("=\"realm\",");
sb.append("qop").append("=\"auth,auth-int\",");
sb.append("nonce").append("=\"").append(getUUID()).append("\",");
sb.append("opaque").append("=\"").append(getUUID()).append("\"");
response.setHeader("WWW-Authenticate",sb.toString());
log.info("authorization:"+sb);
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
}

在这里插入图片描述

在这里插入图片描述

一,用摘要保护密码
摘要认证的一个改进之处是用摘要代替密码的传输,遵循的基本原则是“绝对不通过网络发送明文密码”,而是发送一个密码的摘要信息,并且这摘要信息是不可逆的,即无法通 过摘要信息反推出密码信息。而服务器本身是存储这个密码的(实际上,服务器只需知道密码的摘要即可),而客户端和服务器本身都知道这个密码。这样的话,服务器可以读取客户端的摘要和本身知道的密码进行同样计算得出的摘要进行比较,若匹配,则验证通过。
摘要是对信息主体的浓缩,摘要是一种单向函数,主要用于将无限的输入值转为有限的浓缩输出值,如MD5,则是将任意长度的字节系列转换为一个128位的摘要。MD5输出的128位的摘要通常会写出32个十六进制的字符,每个字符表示4个bit。

二,用随机数防止重放攻击
使用单向摘要就无需以明文形式发送密码了,可以只发送密码的摘要,并且可以确信,没有哪个恶意用户能轻易的从摘要中解码出原始密码。
但是,摘要被截获也可能跟密码一起好用,为了防止重放攻击的发送,服务器可以向客户端发送一个称为随机数nonce的特殊令牌,这个数会经常发生变化(可能是每毫秒,或者每次认证都发生变化,具体由服务器控制),客户端在计算摘要之前要先将这个随机数附加到密码上去。这样,在密码中加入随机数就会使得摘要随着随机数的每次变化而变化,记录下的密码摘要只对特定的随机数有效,而没有密码的话,攻击者就无法计算出正确的摘要,这样就可以防止重放攻击的发生。
摘要认证要求使用随机数,随机数是在WWW-Authenticate服务器质询响应中从服务器传输给客户端的。

  • 5
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值