摘要
出于安全考虑,HTTP规范定义了几种认证方式以对访问者身份进行鉴权,最常见的认证方式之一是Digest认证
Digest认证简介
HTTP通讯采用人类可阅读的文本格式进行数据通讯,其内容非常容易被解读。出于安全考虑,HTTP规范定义了几种认证方式以对访问者身份进行鉴权,最常见的认证方式之一是Digest认证。Digest是一种加密认证方式,通讯中不会传输密码信息,而仅采用校验方式对接入的请求进行验证。
Digest认证支持的加密算法有:SHA256,SHA512/256,MD5。上述这几种算法都是由哈希函数来生成散列值,其加密过程为单向计算,请求方无法反算出密码明文。这里需要强调的是,HTTP认证像其它认证方式一样仅仅对者资源访问进行鉴权,但无法保证通讯过程的安全。
通讯协商过程
发起请求
# <<127.0.0.1:50315
GET / HTTP/1.1
Host: 127.0.0.1:9090
质询
# >>127.0.0.1:50315
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Digest realm="http-auth@mozicoder.org",
nonce="M0P1F4D75VG1IFAJNKA7YG5FW1WRMGCP",
opaque="IGH008EZM3E277G3BXVGWTABKRE6URHK",
algorithm=MD5,
qop="auth"
Server: Mozi.HttpEmbedded/1.4.7.0
请求验证
# >>127.0.0.1:50325
GET / HTTP/1.1
Host: 127.0.0.1:9090
Authorization: Digest realm="http-auth@mozicoder.org",
username="admin",
nonce="M0P1F4D75VG1IFAJNKA7YG5FW1WRMGCP",
uri="/",
algorithm=MD5,
response="1cfe3a00105362cbe5174cb525784f4f",
opaque="IGH008EZM3E277G3BXVGWTABKRE6URHK",
qop=auth,
nc=00000001,
cnonce="0698175c27a8bcee"
校验并返回
# >>127.0.0.1:50325
HTTP/1.1 200 OK
Server: Mozi.HttpEmbedded/1.4.7.0
Digest认证的参数
服务端
realm
认证域。明文信息,用于提示客户端使用哪些用户名和密码。这个值可以设置成任意字符串,建议不要超出ASCII范畴。建议设置成 {string}@{domain} 这种格式,例如:http-auth@mozicoder.org。
domain
受保护的域名信息。以空格为分割,可以是绝对地址,也可以是相对路径。
nonce
随机数。用于参与加密运算,其值取决于服务端如何生成这个参数值。推荐使用B64字符串或HEX字符串。服务端可通过算法实现none的有效时间来防止重放攻击。
opaque
透传字符串。客户端在请求中附带同样的参数值。
stale
随机数是否过期。用于指示客户端认证信息中的随机数是否过期。
algorithm
算法类型。算法类型包括SHA256,SHA512/256,MD5。如果参数列表中没有出现这个值,则默认使用MD5。建议使用MD5。
qop
加密质量。可选值为auth,auth-int。具体区别请文章中的算法实现。
charset
字符集。其唯一可以设置的值为"UTF-8"。一般不设置这个值,这个参数意义不大。
userhash
是否将用户名也进行加密。取值范围:true|false,默认不进行设置,也就是false。
客户端
realm
认证域。明文信息,用于提示客户端使用哪些用户名和密码。使用服务端返回的字符串。
response
加密结果。此值是加密检验的最终对比对象。
username
用户名。
username*
扩展的用户名。当用户名中出现了不符合ABNF范式的字符串的时候,使用这个参数设置用户名和密码,同时也要满足userhash=false这个条件。
uri
路径信息。指示当前正在请求的路径信息,值为相对于根路径的相对路径。
qop
加密质量。可选值为auth,auth-int。具体区别请文章中的算法实现。
cnonce
客户端随机数。用于参与加密运算,其值取决于客户端如何生成这个参数值。推荐使用B64字符串或HEX字符串。服务端可通过算法实现none的有效时间来防止重放攻击。
nc
客户端请求校验的次数。是一个16进制的数值,表示同一nonce下客户端发送出请求的数量。
userhash
是否将用户名也进行加密。取值范围:true|false,默认不进行设置,也就是false。注意:上述参数值仅username, realm, nonce, uri,response, cnonce, and opaque这几个字段可以使用""进行包裹。
Digest认证的验证算法
response=H(HA1:HD:HA2)
//如果加密算法以"-sess"结束
if !algorithm.EndWith("-sess")
{
HA1=H(username:realm:password)
}else{
HA1=H(username:realm:password: nonce:cnonce)
}
HD=nonce:nc:cnonce:qop
if qop!="auth-int"
{
HA2=H(Method:url)
}else{
HA2=H(Method:url:Body-Length)
}
参考文档
[RFC7616] R. Shekh-Yusef, Ed.D. Ahrens,S. Bremer,"HTTP Digest Access Authentication"