HTTP通讯安全中的Digest摘要认证释义与实现

摘要

出于安全考虑,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"

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
HttpClient可以通过提供的CredentialsProvider接口来实现digest认证。下面是一个示例代码: ```java import org.apache.http.HttpEntity; import org.apache.http.HttpHost; import org.apache.http.auth.AuthScope; import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.CredentialsProvider; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.protocol.HttpClientContext; import org.apache.http.impl.auth.DigestScheme; import org.apache.http.impl.client.BasicCredentialsProvider; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils; import java.io.IOException; public class DigestAuthExample { public static void main(String[] args) throws IOException { String username = "user"; String password = "password"; HttpHost target = new HttpHost("localhost", 8080, "http"); CredentialsProvider credsProvider = new BasicCredentialsProvider(); credsProvider.setCredentials( new AuthScope(target.getHostName(), target.getPort()), new UsernamePasswordCredentials(username, password)); CloseableHttpClient httpClient = HttpClients.custom() .setDefaultCredentialsProvider(credsProvider) .build(); HttpClientContext context = HttpClientContext.create(); HttpGet httpGet = new HttpGet("/"); CloseableHttpResponse response = httpClient.execute(target, httpGet, context); try { HttpEntity entity = response.getEntity(); EntityUtils.consume(entity); } finally { response.close(); } // Get the digest scheme from the context DigestScheme digestScheme = (DigestScheme) context.getAuthScheme(target); // Use the digest scheme to generate the next request's headers HttpGet httpGet2 = new HttpGet("/"); httpGet2.addHeader(digestScheme.authenticate( new UsernamePasswordCredentials(username, password), httpGet2, context)); CloseableHttpResponse response2 = httpClient.execute(target, httpGet2, context); try { HttpEntity entity = response2.getEntity(); EntityUtils.consume(entity); } finally { response2.close(); } } } ``` 这个示例代码,使用了BasicCredentialsProvider来提供用户名和密码。当httpClient执行第一次请求时,服务器返回401 Unauthorized响应,httpClient会尝试使用提供的凭据进行认证。然后,httpClient会使用DigestScheme生成下一个请求的摘要认证头。在第二次请求httpClient使用这个头来进行认证

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JasonWcx

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值