3. Digest 访问认证方案 (Digest Access Authentication Scheme)
3.1 引言
3.1.1 目的
被称为 "HTTP/1.0" 的协议中包含了 Basic 访问认证方案 [1] 的规范.该方案并不被视为安全的用户认证方法, 因为用户名和密码会以未加密的形式在网络上传输.本节给出了一种不会以明文发送密码、而是改用校验和技术的方案规范, 该方案称为 "Digest 访问认证 (Digest Access Authentication)".
Digest 访问认证方案并不打算作为万维网安全需求的完整答案.该方案并不提供消息内容加密.它的目的只是构造一种访问认证方法, 以规避 Basic 认证最严重的缺陷.
3.1.2 整体工作方式
和 Basic 访问认证一样, Digest 方案基于一种简单的挑战-响应范式.Digest 方案使用一个 nonce 值来发起挑战.一个有效的响应中包含用户名、密码、给定的 nonce 值、HTTP 方法以及被请求 URI 的校验和 (默认是 MD5 校验和).通过这种方式, 密码永远不会以明文形式发送.与 Basic 一样, 用户名和密码必须通过某种不在本文档讨论范围内的方式预先约定.
3.1.3 摘要值的表示
一个可选首部允许服务器指定用来生成校验和或摘要的算法.默认使用 MD5 算法, 并且它也是本文档中唯一描述的算法.
在本文档中, 一个 128 比特的 MD5 摘要表示为 32 个可打印 ASCII 字符.该 128 比特摘要的比特位从最高有效位到最低有效位, 每 4 比特一组, 被转换成如下 ASCII 表示形式.每 4 比特使用熟悉的十六进制字符 0123456789abcdef 来表示.也就是说, 二进制 0000 表示为字符 '0', 0001 表示为 '1', 依此类推, 直到 1111 表示为 'f'.
3.1.4 局限性
本文档中描述的 Digest 认证方案存在许多已知局限.它的目标只是替代 Basic 认证, 仅此而已.它是一个基于密码的系统, 并且在服务器端也会面临任何密码系统都会遇到的那些问题.尤其是, 本协议并未规定用户与服务器之间初始建立用户密码时的安全协商机制.
用户和实现者应当意识到, 该协议不如 Kerberos 安全, 也不如任何基于客户端私钥的方案安全.尽管如此, 它总比没有强, 比 telnet 和 ftp 中常见的做法更好, 也比 Basic 认证更好.
3.2 Digest 首部的规范
Digest 访问认证方案在概念上与 Basic 方案相似.下面规定了修改后的 WWW-Authenticate 首部行和 Authorization 首部行的格式.此外, 还规定了一个新的首部 Authentication-Info.
3.2.1 WWW-Authenticate 响应首部
如果服务器收到一个针对受访问保护对象的请求, 而该请求未携带可接受的 Authorization 首部, 那么服务器就会返回一个 401 Unauthorized 状态码, 并按上述框架返回一个 WWW-Authenticate 首部.对于 Digest 方案, 其使用方式如下:
challenge = "Digest" digest-challenge
digest-challenge = 1#( realm | [ domain ] | nonce |
[ opaque ] |[ stale ] | [ algorithm ] |
[ qop-options ] | [auth-param] )
domain = "domain" "=" <"> URI ( 1*SP URI ) <">
URI = absoluteURI | abs_path
nonce = "nonce" "=" nonce-value
nonce-value = quoted-string
opaque = "opaque" "=" quoted-string
stale = "stale" "=" ( "true" | "false" )
algorithm = "algorithm" "=" ( "MD5" | "MD5-sess" | token )
qop-options = "qop" "=" <"> 1#qop-value <">
qop-value = "auth" | "auth-int" | token
上面这些指令值的含义如下:
realm
- 一个展示给用户的字符串, 让用户知道应当使用哪个用户名和密码.该字符串至少应包含执行认证的主机名称, 还可以额外指明可能具有访问权限的用户集合.例如可以是
"[email protected]".
domain
- 一个带引号、以空格分隔的 URI 列表, 用于定义保护空间.如果某个 URI 是
abs_path, 那么它相对于当前访问服务器的规范根 URL.该列表中的absoluteURI可以指向一个不同于当前访问目标的服务器.如果省略该指令, 或者其值为空, 客户端应当假定该保护空间由响应服务器上的全部 URI 组成.
nonce
- 一个由服务器指定的数据字符串, 每次生成 401 响应时都应唯一生成.建议该字符串使用 Base64 或十六进制数据.
nonce对客户端来说是不透明的.
opaque
- 一个由服务器指定的数据字符串.对于后续所有 URI 位于同一保护空间内的请求, 客户端都应当在
Authorization首部中原样返回它.
stale
- 一个标志, 表示客户端之前的请求因为
nonce值过期而被拒绝.如果stale为TRUE(不区分大小写), 客户端可以直接使用新的加密响应重试该请求, 而无需再次提示用户输入新的用户名和密码.
algorithm
- 一个字符串, 指示用来生成摘要和校验和的一组算法.如果该字段不存在, 则默认视为
"MD5".如果该算法无法被理解, 则应忽略该挑战.
qop-options
- 该指令是可选的, 但之所以如此仅仅是为了与 RFC 2069 [6] 保持向后兼容; 所有符合本版 Digest 方案的实现都 SHOULD 使用它.如果存在, 它是一个带引号的字符串, 其中包含一个或多个令牌, 用于指出服务器支持的 "保护质量 (quality of protection)" 值.值
"auth"表示认证; 值"auth-int"表示带完整性保护的认证.无法识别的选项 MUST 被忽略.
3.2.2 Authorization 请求首部
客户端应当重试该请求, 并携带一个 Authorization 首部行, 其中 response 指令的值按下述方式计算.
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
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"
3.2.3 Authentication-Info 首部
服务器 MAY 在响应中使用 Authentication-Info 首部字段来传递与成功认证相关的信息.该首部对于 "auth-int" 这种保护质量尤其有用.
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 <">
3.3 Digest 的工作过程
Digest 访问认证的工作过程如下.客户端向服务器发起请求, 服务器通过一个 401 响应发起挑战, 其中提供 nonce 和其他参数.客户端使用这些参数计算 response 值, 并在后续请求中连同其他信息一起发送给服务器.服务器验证该 response 值; 如果正确, 则授予访问权限.
3.4 安全协议协商
服务器可以在 WWW-Authenticate 首部中提供多个挑战, 每个挑战使用不同的认证方案.客户端 SHOULD 选择其所支持的最强方案.
3.5 示例
下面的示例假设访问受保护文档需要认证.服务器通过一个 401 响应发起挑战:
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Digest
realm="[email protected]",
qop="auth,auth-int",
nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",
opaque="5ccc069c403ebaf9f0171e9517f40e41"
客户端可以使用如下 Authorization 首部进行响应:
Authorization: Digest username="Mufasa",
realm="[email protected]",
nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",
uri="/dir/index.html",
qop=auth,
nc=00000001,
cnonce="0a4f113b",
response="6629fae49393a05397450978507c4ef1",
opaque="5ccc069c403ebaf9f0171e9517f40e41"
3.6 Proxy-Authentication 与 Proxy-Authorization
代理认证与授权的工作方式与源服务器认证和授权类似, 但它们使用 Proxy-Authenticate 和 Proxy-Authorization 首部字段.代理在处理客户端与源服务器之间的认证时 MUST 保持完全透明.