HTTP认证之摘要认证——Digest(一)
导航
一、概述
Digest认证是为了修复基本认证协议的严重缺陷而设计的,秉承“绝不通过明文在网络发送密码”的原则,通过“密码摘要”进行认证,大大提高了安全性。
相对于基本认证,主要有如下改进:
- 绝不通过明文在网络上发送密码
- 可以有效防止恶意用户进行重放攻击
- 可以有选择的防止对报文内容的篡改
需要注意的是,摘要认证除了能够保护密码之外,并不能保护其他内容,与HTTPS配合使用仍是一个良好的选择。以下是摘要认证的具体流程图:
看到上面出现了那么多之前没见过的参数,是不是有点慌(或是兴奋)?别着急,这里先给出一个概览:
WWW-Authentication
:用来定义使用何种方式(Basic、Digest、Bearer等)去进行认证以获取受保护的资源realm
:表示Web服务器中受保护文档的安全域(比如公司财务信息域和公司员工信息域),用来指示需要哪个域的用户名和密码qop
:保护质量,包含auth
(默认的)和auth-int
(增加了报文完整性检测)两种策略,(可以为空,但是)不推荐为空值nonce
:服务端向客户端发送质询时附带的一个随机数,这个数会经常发生变化。客户端计算密码摘要时将其附加上去,使得多次生成同一用户的密码摘要各不相同,用来防止重放攻击nc
:nonce计数器,是一个16进制的数值,表示同一nonce下客户端发送出请求的数量。例如,在响应的第一个请求中,客户端将发送“nc=00000001”。这个指示值的目的是让服务器保持这个计数器的一个副本,以便检测重复的请求cnonce
:客户端随机数,这是一个不透明的字符串值,由客户端提供,并且客户端和服务器都会使用,以避免用明文文本。这使得双方都可以查验对方的身份,并对消息的完整性提供一些保护response
:这是由用户代理软件计算出的一个字符串,以证明用户知道口令Authorization-Info
:用于返回一些与授权会话相关的附加信息nextnonce
:下一个服务端随机数,使客户端可以预先发送正确的摘要rspauth
:响应摘要,用于客户端对服务端进行认证stale
:当密码摘要使用的随机数过期时,服务器可以返回一个附带有新随机数的401响应,并指定stale=true
,表示服务器在告知客户端用新的随机数来重试,而不再要求用户重新输入用户名和密码了
二、剖析
1.当打开需要认证的页面时,会弹出一个对话框,要求用户输入用户名和密码
2.使用Fidder监听请求,可以看到在未进行认证或认证失败的情况下,服务端会返回401 Unauthorized
给客户端,并附带Challenge
3.输入正确的用户名和密码后,浏览器会生成密码摘要以及其他信息发送给服务端,服务端认证成功后,返回一些与授权会话相关的附加信息,放在Authorization-Info
中。
其中,客户端选择的保护质量策略为auth
,response
就是通过计算得到的密码摘要,具体计算方式如下(使用默认的MD5加密算法):MD5(MD5(A1):<nonce>:<nc>:<cnonce>:<qop>:MD5(A2))
算法 | A1 |
---|---|
MD5(默认) | <username>:<realm>:<password> |
MD5-sess | MD5(<username>:<realm>:<password>):<nonce>:<cnonce> |
qop | A2 |
---|---|
auth(默认) | <request-method>:<uri> |
auth-int | <request-method>:<uri>:MD5(<request-entity-body>) |
另外,rspauth
使得客户端可以对服务器进行认证,称为响应摘要。响应摘要的计算与请求摘要类似,但由于响应中没有方法,而且报文实体数据有所不同,所有只有报文主题信息A2不同。具体区别如下:
qop | A2 |
---|---|
auth(默认) | :<uri> |
auth-int | :<uri>:MD5(<response-entity-body>) |
4.当服务端随机数过期时,再次请求认证,可以看到质询中增加了stale=true
,用户无需再次输入用户名和密码,浏览器会自动使用新的质询参数进行密码摘要的计算。
三、注意事项
1.预授权:服务端预先告知客户端下一个随机数是多少,使得客户端可以直接生成正确的Authorization
首部,避免了多次“请求/质询”。常用的有一下三种方式:
- 服务器预先在
Authorization-Info
成功首部中发送下一个随机数nextnonce
。虽然这种机制加快了事务处理的速度,但是它也破坏了对同一台服务器的多次请求进行管道化的功能,可能会造成很大的损失。 - 服务器允许在一小段时间内使用同一个随机数。这也就是我们上面剖析中使用的机制,在一定时间内使用同一个随机数或限制某个随机数的重用次数,当过期时,声明
stale=true
。虽然这确实降低了安全性,但是重用的随机数的生存周期是可控的,应该在安全和性能之间找到平衡。 - 客户端和服务器使用同步的、可预测的随机数生成算法。
2.RFC 2617建议采用这个假想的随机数公式:BASE64(timestamp MD5(timestamp ":" ETag ":" private-key))
其中,timestamp
是服务器产生随机数的时间或其他不重复的值,ETag
是与所请求实体有关的HTTP ETag首部的值,private-key
是只有服务器知道的私钥。