HTTP基本认证&摘要认证(带你一步步算出摘要)

HTTP的质询/响应认证框架

认证协议与首部

HTTP 通过一组可定制的控制首部,为不同的认证协议提供了一个可扩展框架。

步骤 首部 描述 方法/状态
请求 第一条没有认证信息 GET
质询 WWW-Authenticate 服务器用 401 状态拒绝了请求,说明需要用户提供用户名和密码。 401 Unauthorized
授权 Authorization 客户端重新发出请求,但这一次会附加一个Authorization首部,用来说明认证算法、用户名和密码 GET
成功 Authentication-Info 如果授权证书是正确的,服务器就会将文档返回。 200(基本认证没有此首部)

基本认证

我的这篇博客里面,有对HTTP基本认证的一个示例。

摘要认证

基本认证便捷灵活,但极不安全。用户名和密码都是以明文形式(只用Base64编码进行了扰码,没有任何防止用户攻击的手段)传送的。

摘要认证的改进

摘要认证是另一种 HTTP 认证协议,它试图修复基本认证协议的严重缺陷。具体来说,摘要认证进行了如下改进。

  • 永远不会以明文方式在网络上发送密码。
  • 可以防止恶意用户捕获并重放认证的握手过程。
  • 可以有选择地防止对报文内容的篡改。
  • 防范其他几种常见的攻击方式。

网上有很多文章详细介绍了摘要认证,这里我就简单的说明一下摘要认证是什么原理,怎么改进了基本认证的缺陷。

首先基本认证的一个重大缺陷就是在请求中使用了Base64加密来传输了用户名和密码,Base64是对称加密,也就意味着如果有人截获了请求,那么就相当于用户名和密码全部暴露了,这是非常危险的事情。

所以摘要认证的基本原则就是绝不通过网络发送明文密码,而是发送一个密码的摘要信息来取代密码,并且这个摘要信息是不可逆的,也就是我们需要用非对称加密算法来加密。例如md5加密。比如客户端需要加密的信息是hello world,经过md5加密后请求发送的是5eb63bbbe01eeed093cb22bb8f5acdc3这一串密文,任何人截获到这段密文是无法反推回hello world的,然后服务端收到这个密文后。他先去数据库中找到你存储的密文hello world(当然是根据你传过来的未加密的用户名来找的,我们省略了没说),然后服务端也对hello world进行md5加密,对比加密后的字符串和客户端发过来的,当然一样啦,那就验证通过了。

当然,这里会有一个严重的问题,黑客截获了摘要信息和密码一样好用,他只要伪造请求,然后把摘要信息再发给服务端就照样可以为所欲为了。那么怎么办呢?加随机数就可以解决。服务端第一次发一个随机串randomStr给客户端,当然,服务端自己也记下来我发了这个随机串给客户端,然后客户端拿到randomStr后,附在密码后面再执行md5加密,然后再把密文发给服务端。这时候就很好了,服务端也是会先把随机串附在密码后面,然后md5加密得到密文,来和客户端发过来的比较。但是现在即使这个密文被截获了也没用,因为这个密文是根据一个服务端的随机数来生成的,而这个随机数服务端可以设置每次请求或者每一毫秒都不一样,而黑客却无法得知。

示例:

说了这么多,不如举个例子来演示一下摘要是怎么算出来的,这样更容易理解这个东西。下面我就来带大家算一下这个摘要。

这里我用Node起了一个简单的HTTP服务,在/digest上加了一个简单的摘要认证。

if (req.url === '/digest') {
    if (!req.headers['authorization']) {
      // 这里很粗暴,如果客户端请求头中没有`authorization`首部,则直接401请求进行摘要认证,记住这里的`realm`和`qop`和`nonce`,后面计算摘要的时候会用到
      res.writeHead(401, {
        'WWW-Authenticate': 'Digest realm="blog.csdn.net" qop="auth" nonce="C1A5298F939E87E8F962A5EDFC206918"'
      })
      res.end('no permissiion')
    } else {
      res.writeHead(200, {
        'Content-Type': 'text/plain'
      })
      // 如果请求头中有`authorization`首部,则显示出来,便于我们一会儿拿来计算摘要
      res.end(req.headers['authorization'])
    }
  }
  1. 打开/digest,弹出密码框,注意realm的信息是会显示出来的,realm直译过来是领域、范围的意思,实际上这个字段是告诉用户这个权限的是用来干嘛的。
    HTTP基本认证&摘要认证(带你一步步算出摘要)_第1张图片

  2. 然后我们输入用户名admin,密码123456,然后点击确定,这时候客户端会计算好摘要然后放到请求头Authorization首部中再发一次请求。
    HTTP基本认证&摘要认证(带你一步步算出摘要)_第2张图片
    3.然后上面说了,一旦有这个头部,我就返回200,而且直接返回头部,这下知道为啥要这么做了吧,方便看啊:)
    在这里插入图片描述
    4.好了,下面我们来看一下客户端生成了哪些字段。主要有responsencconce三个字段,response字段是最终的摘要。现在我们一起来根据这些字段,手动计算出这个response,这样我们就说明我们可以在服务端进行验证了。
    在这里插入图片描述
    5.首先response的值是7715f35b1e325c9c8952296166d9939c
    根据摘要算法介绍,我们先得到A1 = ::admin:blog.csdn.net:123456A2=:GET:/digest
    然后对A1A2进行md5加密:

    名称 加密前 加密后
    A1 admin:blog.csdn.net:123456 be127d36de3549d7d1e6fa451aef7ce2
    A2 GET:/digest 72c5182fbc56def0cfe368cd32b37c29

    然后根据最后计算摘要的公式MD5(MD5(A1):::::MD5(A2)),我们需要计算be127d36de3549d7d1e6fa451aef7ce2:C1A5298F939E87E8F962A5EDFC206918:00000001:5de05b4c5cedc081:auth:72c5182fbc56def0cfe368cd32b37c29的MD5值,然后来比较和response是否一致。
    HTTP基本认证&摘要认证(带你一步步算出摘要)_第3张图片
    我们计算出的结果为7715f35b1e325c9c8952296166d9939c。看本条的开头的response值,是不是和我们计算出来的一样呢。

    额外补充一句,每次请求时,nccnonce都会变。是不是觉得摘要认证比基本认证要安全很多呢。

2019年6月更新,cnoncenc在官方文档中的说明

cnonce
This MUST be specified if a qop directive is sent (see above), and
MUST NOT be specified if the server did not send a qop directive in
the WWW-Authenticate header field. The cnonce-value is an opaque
quoted string value provided by the client and used by both client
and server to avoid chosen plaintext attacks, to provide mutual
authentication, and to provide some message integrity protection.
See the descriptions below of the calculation of the response-
digest and request-digest values.

nonce-count
This MUST be specified if a qop directive is sent (see above), and
MUST NOT be specified if the server did not send a qop directive in
the WWW-Authenticate header field. The nc-value is the hexadecimal
count of the number of requests (including the current request)
that the client has sent with the nonce value in this request. For
example, in the first request sent in response to a given nonce
value, the client sends “nc=00000001”. The purpose of this
directive is to allow the server to detect request replays by
maintaining its own copy of this count - if the same nc-value is
seen twice, then the request is a replay. See the description
below of the construction of the request-digest value.

(另外,我已不再在csdn更新博客,今天是因为在csdn旗下的gitchat买了个课程然后登录了账号看到提示消息才进来的。csdn博客广告太多了,受不了,迁移到简书去了简书地址)

你可能感兴趣的:(学习笔记)