auth-param
该指示用于未来扩展。任何无法识别的指示都必须被忽略。
3.2.2 授权请求标题(The Authorization Request Header)
客户端想重试发送请求,并传递对应前面所框架定义的授权标题行,如下:
credentials = "Digest" digest-response
digest-response = 1#( username | realm | nonce | digest-uri
|response | [ algorithm ] | [cnonce] |
[opaque] | [message-qop] |
[nonce-count] | [auth-param] )
username = "username" "=" username-value
username-value = quoted-string
digest-uri = "uri" "=" digest-uri-value
digest-uri-value = request-uri ; As specified by HTTP/1.1
message-qop = "qop" "=" qop-value
cnonce = "cnonce" "=" cnonce-value
cnonce-value = nonce-value
nonce-count = "nc" "=" nc-value
nc-value = 8LHEX
response = "response" "=" request-digest
request-digest = <"> 32LHEX <">
LHEX = "0" | "1" | "2" | "3" |
"4" | "5" | "6" | "7" |
"8" | "9" | "a" | "b" |
"c" | "d" | "e" | "f"
opaque域和算法(algorithm)域的值必须在被请求实体的WWW-鉴别回应标题中给出。
response
是个字符串,由32个经过计算的16进制数字组成,用来证明用户是否知道口令。
username
用户名,是指定的realm项。
Franks, et al. Standards Track [Page 11]
digest-uri
从请求队列(Request-Line)中的请求URI得到的URI;这里存在副本是因为代理(proxy)在传送时允许对请求队列进行修改。
qop
指示客户端对该消息应用的保护等级(quality of protection)。如果不为空,其值必须是服务器支持在WWW-鉴别标题中采用的几种值之一。这些值会对请求-分类(request-digest)的计算造成影响。注意,这是个单独的符号,而不是象WWW-鉴别(WWW- Authenticate)那样,是带引号的可选值列表。该指示是可选项,这是为了和RFC2069[6]所规定的最小实现保持向后的兼容性。但是,如果服务器端通过在WWW-鉴别(WWW- Authenticate)标题域中添加qop指示,就表明该服务器支持qop,因而,必须使用该项指示。
cnonce
当qop指示发送了(见上面),该指示必须要指定,而当服务器端没有在WWW-鉴别(WWW- Authenticate)标题域中添加qop指示时,该指示一定不能指定。cnonce-value是客户端提供的字符串,它由客户端和服务器共同使用,用来避免选择纯文本攻击、提供共同鉴别、提供某些消息的完整性保护。详情见下面的回应分类(response-digest)值和请求-分类(request-digest)值的计算。
nonce-count
当qop指示发送了(见上面),该指示必须要指定,而当服务器端没有在WWW-鉴别(WWW- Authenticate)标题域中添加qop指示时,该指示一定不能指定。nc-value是16进制表示的计数值,用来统计客户端发送的带nonce值的请求(包括当前请求)个数。例如,在第一个请求回应中给出了nonce的值,客户端发送”nc=00000001",其目的是允许服务器通过对此计算副本的维护来检测请求重复(request replay),即当同样的nc-value出现两次,说明请求是可回放的。详情见下面请求-分类(request-digest)值的构建。
auth-param
该指示用于未来扩展。任何无法识别的指示都应被忽略。
如果指示或其值不正确,或者需要的指示没有给出,都会得到400(非法请求)回应。如果请求-分类(request-digest)是非法的,登录失败将会被记入日志,因为在某个单独的客户端出现的重复登录失败可能意味着攻击者正试图猜测口令。
Franks, et al. Standards Track [Page 12]
前面定义的请求-分类(request-digest)指示了其编码方式。下面的定义将表明这些值是如何参与计算的。
3.2.2.1 请求-分类(Request-Digest)
如果”qop”值是"auth" 或"auth-int":
request-digest = <"> < KD ( H(A1), unq(nonce-value)
":" nc-value
":" unq(cnonce-value)
":" unq(qop-value)
":" H(A2)
) <">
如果”qop”指示没有给出(与RFC2069保持兼容性):
request-digest =<"> < KD ( H(A1), unq(nonce-value)
":" H(A2)
) <">
A1及A2的定义在下面。
3.2.2.2 A1
如果算法("algorithm")值是”MD5”或没有指定,则A1是:
A1 = unq(username-value) ":" unq(realm-value) ":" passwd
其中
passwd = < user's password >
如果"algorithm"值是"MD5-sess",则A1只要计算一次,即当客户端发出第一个请求,并从服务器收到WWW-鉴别(WWW-Authenticate)质询(challenge)时计算。它使用该质询中的服务器的nonce,则用来构建A1的第一个客户端nonce值应为:
A1 = H( unq(username-value) ":" unq(realm-value)
":" passwd )
":" unq(nonce-value) ":" unq(cnonce-value)
上式为并发请求和回应的鉴别产生一个‘会话密钥’(session key),该密钥对于每个‘鉴别会话’(authentication session)都是不同的,这样,就限制了使用任何一个密钥进行哈希处理的次数(注意:鉴别会话更深层次的探讨见3.3节)。
Franks, et al. Standards Track [Page 13]
因为服务器只需要使用用户信任的哈希值来产生A1值,因而该机制可允许第三方参与鉴别服务,这样WEB服务器就不再需要实际的口令值了。该协议的规范已经超出了本规范的内容范围。
3.2.2.3 A2
如果”qop”值是”auth”或者没给出,则A2:
A2 = Method ":" digest-uri-value
如果"qop"值是"auth-int", 则A2:
A2 = Method ":" digest-uri-value ":" H(entity-body)
3.2.2.4 指示值和带引号的字符串(Directive values and quoted-string)
注意,许多指示的取值,如”username-value”等,被定义成带引号的字符串(quoted-string)。而实际上,”unq”注释则表示在生成字符串A1时,去掉其外部的引号。因而,如当授权标题包括该域,如:
username="Mufasa", realm=myhost@testrealm.com
则表示用户Mufasa的口令是"Circle Of Life",这样H(A1)就可表示成
H(Mufasa:myhost@testrealm.com:Circle Of Life),注意,在分类字符串中没有引号。
注意,在分类函数H()中的字符串中不允许出现空格,除非空格出现在带引号的字符串内或者用以标记字符串分类的实体主体中。例如,上面出现的字符串A1必须是
Mufasa:myhost@testrealm.com:Circle Of Life
在冒号的两边都不可以有空格,但是允许口令单词之间出现空格(Circle+SP+Of+SP+Life)。同样,其它由H()分类的字符串也不能在用于域间分隔的冒号两边加空格,除非空格在引号内或被分类的实体主体内。
同样要注意的是,如果应用了完整性保护(integrity protection),即qop=auth-int,则H(实体-主体)就是实体主体的哈希值,而不是消息主体的哈希值,该值在发送方进行任何传输编码前计算,之后,被接收方删除。
Franks, et al. Standards Track [Page 14]
注意,它在任何多部分内容-类型(multipart content-type)中的每个部分都包括多部分的边界和嵌入标题。
3.2.2.5 多样性考虑(Various considerations)
"Method"(方法)值是指HTTP请求的方法,见[2]的5.1.1节。"request-uri"值请求队列中指定的请求URI,见[2]的5.1.2节。可能还会有”*”号,即绝对URL("absoluteURL" 或 "abs_path"),见[2]的5.1.2节,但必须与请求URI保持一致。特殊情况,当请求URI是绝对URL时,它也必须是绝对URL形式。"cnonce-value"是客户端可选的值,用来防止纯文本攻击。
进行鉴别的服务器必须保证"uri"所指向的资源与请求队列中指定的资源相同;如果不同,服务器应当回应400(非法请求)消息。注意,由于这可能是攻击的前兆,服务端的实现可能要对此进行日志记录。
在该域的请求URL中包含重复信息的目的是因为中间的代理服务器可能会更改客户端的请求队列。已经更改的请求(尽管可以恢复原状)将会导致由客户端计算的分类发生变更。
开发者应当注意己鉴别的事务是如何与共享缓存进行交互的。HTTP/1.1协议规定,如果共享缓存(见[2]的13.7)收到的请求中所包含的授权标题和回应是由请求中继传来的,此时一定不能将该回应做为对其它请求的回答,除非是回应中包括两种缓存-控制(Cache-Control)指示中的任何一种才可以。
如果原始服务器回应中指明"must-revalidate"(必须重新授权)的缓存控制指示,缓存虽然可以在回应并发请求时使用该回应的实体,但必须先从原始服务器处得到认可才行,认可的方法是用新请求的请求标题到原始服务器处获取授权。同样,如果原始服务器回应中包括”public”缓存控制指示,则对任何并发请求都可应用此回应的实体。
3.2.3 鉴别信息标题(The Authentication-Info Header)
Authentication-Info标题被服务器用做通讯区,以得到回应中鉴别成功的一些信息。
Franks, et al. Standards Track [Page 15]
AuthenticationInfo = "Authentication-Info" ":" auth-info
auth-info = 1#(nextnonce | [ message-qop ]
| [ response-auth ] | [ cnonce ]
| [nonce-count] )
nextnonce = "nextnonce" "=" nonce-value
response-auth = "rspauth" "=" response-digest
response-digest = <"> *LHEX <">
nextnonce值是服务器希望客户端在未来鉴别回应中采用的nonce值。服务器可能发送带有nextnonce域的Authentication-Info标题,以实现一次性或可变的鉴别方式。如果nextnonce域有值,客户端应当在下次请求中使用该值来构建授权标题。如果有"stale=TRUE"存在,客户端的失败将导致服务器端对请求进行重新鉴别。
服务器的实现应当小心处理采用这种机制而引发的潜在性能问题;如果每个请求都包括由服务器指定的、必须在下个请求时使用的nextnonce值,那么管道式(pipelined)请求不可能实现。要想实现管理式请求,而且要顾及性能和安全性的平衡,可在一段有限时间内,允许使用旧的nonce值。使用nonce-count可以在不危害管道的前提下,保留新服务器nonce的大多数安全特性。
message-qop
表示用于服务器回应的保护等级选项。"auth"值表示鉴别;而"auth-int"值则表示采用完整性保护的鉴别。服务器在回应客户端请求时,应当采用和message-qop相同的值。
在"response-auth"中的可选回应分类支持相互鉴别,即服务器可以证实它知道用户的秘密,也可通过qop=auth-int对回应提供有限的完整性保护。"response-digest"值用于授权标题中的"request-digest"值的计算,除非指定请求的授权标题中包含"qop=auth"或没指定,则A2是:
A2 = ":" digest-uri-value
若包含"qop=auth-int", 则A2 是:
A2 = ":" digest-uri-value ":" H(entity-body)
Franks, et al. Standards Track [Page 16]
其中,"digest-uri-value"是请求中授权标题所指向的"uri"。而"cnonce-value"和"nc- value"必须做为客户端请求的回应消息的组成部分。当指定了"qop=auth"或"qop=auth-int"时,"response-auth"、"cnonce"、和"nonce-count"必须给出。
Authentication-Info标题允许对通过块编码(chunked transfer-coding)传输的HTTP消息进行追踪。
3.3 分类操作(Digest Operation)
在接收授权标题前,服务器可能要先检查对应用户名、口令的合法性。这时,服务器必须执行和客户端相同的分类操作(如,MD5),并将结果与给定请求-分类(request-digest)相比较。
注意,HTTP服务器只要支持H(A1),就不必知道用户的口令明文,而授权标题的合法性照样可以鉴别。
客户端在回应对受保护区间的WWW-鉴别(WWW-Authenticate)质询时,启动同该受保护区间之间的鉴别会话。鉴别会话在客户端收到受保护区中的任何服务器发出的WWW-鉴别(WWW-Authenticate)质询时终止。客户端应当记住与鉴别会话相关的username、password、nonce、nonce count及opaque值,从而能构建将来对指定保护区请求的授权标题。授权标题要被优先包括,这样做会提高服务器效率,并避免鉴别质询可能发生的额外循环。服务器可能选择接受旧的授权标题信息,即使其中包含的nonce值已过期。同样,服务器可能回应401,其中包括了新的nonce值,这样会引起客户端重试该请求;通过在回应中指定stale=TRUE,服务器通知客户端用新的nonce来重试请求,但是不会再要求输入新的用户名及口令。
因为客户端在会话期间要把服务器传给它的opaque值返回给服务器,opaque值可用来传递鉴别会话的状态信息。(注意,其实可通过在nonce中包括状态的方法来实现,这样更安全、简单。)例如,服务器要为已经位于其它服务器的鉴别内容负责,其实现是,在第一个401回应中包括domain指示(包括第二个服务器上的URI)和opaque指示(包括状态信息)
Franks, et al. Standards Track [Page 17]
客户端会在服务器回应301或302(重定向,即,指向第二个服务器上的URI)时重试该请求。客户端会根据重定向信息,传送授权标题,包括<opaque> 数据。
在基本方案中,代理(proxy)必须完全透明地处理分类访问鉴别方案(Digest access authentication scheme.)。他们必须将WWW-Authenticate、Authentication-Info、和Authorization header向前推送,而不做任何修改。如果代理希望在请求推送到服务器之前对客户进行鉴别,它可以使用代理-鉴别(Proxy-Authenticate)和代理-授权(Proxy-Authorization)标题,见下面3.6节。
3.4 安全协议讨论(Security Protocol Negotiation)
对服务器来说,了解客户端有能力处理的哪种安全方案是很有用的。
可能存在这种情况,服务器端直接获取分类做为其鉴别方法,而不管客户端是否支持它。如果发生这种情况,服务器指定的鉴别方案恰好是客户端所不支持的,客户端应当明确回应失败。
3.5 例子(Example)
下面的例子假定通过GET请求来获取服务器上一个带有访问保护的文档。文档的URI是"http://www.nowhere.org/dir/index.html",客户端和服务器都知道该文档的用户名是"Mufasa",口令是"Circle Of Life"(三个单词间用一个空格分隔)。
客户端在第一次请求该文档时,没有发送授权标题,于是服务器回应:
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Digest
realm="testrealm@host.com",
qop="auth,auth-int",
nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",
opaque="5ccc069c403ebaf9f0171e9517f40e41"
客户端可能会在新的请求中提供用户名和口令,包括下面的授权标题:
Franks, et al. Standards Track [Page 18]
Authorization: Digest username="Mufasa",
realm="testrealm@host.com",
nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",
uri="/dir/index.html",
qop=auth,
nc=00000001,
cnonce="0a4f113b",
response="6629fae49393a05397450978507c4ef1",
opaque="5ccc069c403ebaf9f0171e9517f40e41"
3.6 代理鉴别和代理授权(Proxy-Authentication and Proxy-Authorization)
通过使用Proxy-Authenticate和Proxy-Authorization标题,分类鉴别方案也可实现在代理、代理间、代理与原始服务器间进行用户鉴别。这些标题是Proxy-Authenticate和Proxy-Authorization标题的实例(见HTTP/1.1规范[2],10.33和10.34节,其行为的限制描述)。代理鉴别事务与已经描述的十分相似。在接收需要鉴别的请求之前,代理/服务器必须发出407(需要代理鉴别)回应,其中包含了"Proxy-Authenticate"标题。Proxy-Authenticate标题中使用的分类质询(digest-challenge)与在前面3.2.1节中定义的WWW- Authenticate标题一样。
客户端/代理必须重新发出带有代理授权(Proxy-Authorization)标题的请求,其写法见上面的3.2.2节的授权标题。
在并发回应时,服务器将发送代理鉴别信息(Proxy-Authentication-Info),其写法与Authentication-Info标题域是一样的。
注意,原理上,可要求客户端提供对代理和最终服务器的自身鉴别,但不能在同一个回应当中。
4 安全考虑(Security Considerations)
4.1 用基本鉴别的客户端鉴别(Authentication of Clients using Basic Authentication)
基本鉴别方案不是安全的用户鉴别方式,也不会对以明文方式在物理网络中传输的实体进行任何形式的保护。HTTP允许使用另外的鉴别方案或加密机制来增强基本协议的安全性能(比如,一次性口令方案)。
Franks, et al. Standards Track [Page 19]
基本鉴别方式最严重的漏洞在于它将用户口令以明文方式在物理网络中传输,而这正是分类鉴别(Digest Authentication)方式试图去解决的。
因为基本鉴别使用了口令的明文传输方式,因此,如果没有使用增强方式,一定不能用来保护敏感或有价值的信息。
基本鉴别方式通常用于识别目的――要求用户提供用户名及口令做为身份标识,例如,用于服务器精确统计使用状况。这种情况看似没有危险,对受保护文件的违法访问不是主要问题。然而,除非由服务器向用户发送用户名、口令,而且不允许用户选择自己的口令时,这种方式才可能安全。否则危险会成倍增加,因为有些天真的用户为避免维护多个口令,而老是使用单个的口令。
如果服务器允许用户自由选择口令,那带来的危险不仅仅是对服务器文件的未授权访问,而且还会引起对用户用同样口令保护的其它系统资源的未授权访问。此外,在服务器口令数据库中,许多口令同样是用户访问其它站点的口令。因而,如果此类信息不受到安全保护,那么系统的所有者或管理员将会承担因未授权访问而造成的系统用户信息暴露的风险。
基本鉴别也容易受到假冒服务器欺骗的攻击。当用户坚信他正与一台受基本鉴别方案保护的主机相连时,他也许不会想到,此时他可能正与怀有敌意的服务器或网关相连。攻击者可截获口令,并将其储存起来备用,同时假装返回一个错误。这种类型的攻击在分类鉴别方案下是不可能成功的。服务器端的开发者应当实现对假冒网关或伪装CGI script的防护。在特殊情况下,象服务器打开与某个网关的连接之类看起来很简单的事都有可能产生严重后果,因为这样以后,网关就可扮演成原始服务器,用持久连接的机制同客户建立多种事务交互,而客户可能对此一无所知。
4.2 用分类鉴别的客户端鉴别(Authentication of Clients using Digest Authentication)
与其它一些安全机制相比,如基于公钥技术的机制,分类鉴别机制要显得脆弱一些。
Franks, et al. Standards Track [Page 20]