HTTP认证模式:Basic & Digest

引言

经常在工作中使用到了各种认证方式,但从未考虑过这些认证方式所属的知识范畴,同时也解释不清楚它们。

曾用到的认证方式(看看是否您也用过,但很难解释清楚他们):

  • Basic认证(访问API时,浏览器会自动弹出一个对话框去输入用户名/密码)
  • 用户名密码认证(进入站点主页前,需要在登陆页面输入用户名和密码,这种更专业的叫法为表单认证)
  • openID Connect认证(用于第三方登陆认证,比如微信提供给简书的登录认证)
  • Kerberos认证(一种用于Hadoop集群的客户端认证)

经过阅读《图解HTTP协议》这一书后,对HTTP认证方式有了进一步的了解。

1.  basic认证是把用户和密码通过base64加密后发送给服务器进行验证

2.  digest认证则是把服务器响应的401消息里面的特定的值和用户名以及密码结合起来进行不可逆的摘要算法运算得到一个值,然后把用户名和这个摘要值发给服务器,服务通过用户名去 在自己本地找到对应的密码,然后进行同样的摘要运算,再比较这个值是否和客户端发过来的摘要值一样。

TTP协议规范的另一种认证模式是Digest模式,在HTTP1.1时被提出来,它主要是为了解决Basic模式安全问题,用于替代原来的Basic认证模式,Digest认证也是采用challenge/response认证模式,基本的认证流程比较类似,整个过程如下:

①浏览器发送http报文请求一个受保护的资源。

②服务端的web容器将http响应报文的响应码设为401,响应头部比Basic模式复杂,WWW-Authenticate: Digest realm=”myTomcat”,qop="auth",nonce="xxxxxxxxxxx",opaque="xxxxxxxx" 。其中qop的auth表示鉴别方式;nonce是随机字符串;opaque服务端指定的值,客户端需要原值返回。

③浏览器弹出对话框让用户输入用户名和密码,浏览器对用户名、密码、nonce值、HTTP请求方法、被请求资源URI等组合后进行MD5运算,把计算得到的摘要信息发送给服务端。请求头部类似如下,Authorization: Digest username="xxxxx",realm="myTomcat",qop="auth",nonce="xxxxx",uri="xxxx",cnonce="xxxxxx",nc=00000001,response="xxxxxxxxx",opaque="xxxxxxxxx" 。其中username是用户名;cnonce是客户端生成的随机字符串;nc是运行认证的次数;response就是最终计算得到的摘要。

④服务端web容器获取HTTP报文头部相关认证信息,从中获取到username,根据username获取对应的密码,同样对用户名、密码、nonce值、HTTP请求方法、被请求资源URI等组合进行MD5运算,计算结果和response进行比较,如果匹配则认证成功并返回相关资源,否则再执行②,重新进行认证。

⑤以后每次访问都要带上认证头部。

其实通过哈希算法对通信双方身份的认证十分常见,它的好处就是不必把具备密码的信息对外传输,只需将这些密码信息加入一个对方给定的随机值计算哈希值,最后将哈希值传给对方,对方就可以认证你的身份。Digest思想同样采如此,用了一种nonce随机数字符串,双方约好对哪些信息进行哈希运算即可完成双方身份的验证。Digest模式避免了密码在网络上明文传输,提高了安全性,但它仍然存在缺点,例如认证报文被攻击者拦截到攻击者可以获取到资源.

HTTP请求报头: Authorization

HTTP响应报头: WWW-Authenticate

HTTP认证 

基于

 质询 /回应( 

challenge/response)的认证模式。

◆ 基本认证 basic authentication   ← HTTP1.0提出的认证方法

    客户端对于每一个realm,通过提供用户名和密码来进行认证的方式。

    ※ 包含密码的明文传递

    基本认证步骤:

     1. 客户端访问一个受http基本认证保护的资源。

     2. 服务器返回401状态,要求客户端提供用户名和密码进行认证。

           401 Unauthorized

           WWW-Authenticate: Basic realm="WallyWorld"

     3. 客户端将输入的用户名密码用Base64进行编码后,采用非加密的明文方式传送给服务器。

           Authorization: Basic xxxxxxxxxx.

     4. 如果认证成功,则返回相应的资源。如果认证失败,则仍返回401状态,要求重新进行认证。

    特记事项

     1. Http是无状态的,同一个客户端对同一个realm内资源的每一个访问会被要求进行认证。

     2. 客户端通常会缓存用户名和密码,并和authentication realm一起保存,所以,一般不需要你重新输入用户名和密码。

     3. 以非加密的明文方式传输,虽然转换成了不易被人直接识别的字符串,但是无法防止用户名密码被恶意盗用。

◆ 摘要认证 digest authentication   ← HTTP1.1提出的基本认证的替代方法

    服务器端以nonce进行质询,客户端以用户名,密码,nonce,HTTP方法,请求的URI等信息为基础产生的response信息进行认证的方式。

    ※ 不包含密码的明文传递

    

    摘要认证步骤:

     1. 客户端访问一个受http摘要认证保护的资源。

     2. 服务器返回401状态以及nonce等信息,要求客户端进行认证。

HTTP/1.1 401 Unauthorized

WWW-Authenticate: Digest

realm="[email protected]",

qop="auth,auth-int",

nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",

opaque="5ccc069c403ebaf9f0171e9517f40e41"

     3. 客户端将以用户名,密码,nonce值,HTTP方法, 和被请求的URI为校验值基础而加密(默认为MD5算法)的摘要信息返回给服务器。

           认证必须的五个情报:

     ・ realm : 响应中包含信息

     ・ nonce : 响应中包含信息

     ・ username : 用户名

     ・ digest-uri : 请求的URI

     ・ response : 以上面四个信息加上密码信息,使用MD5算法得出的字符串。

Authorization: Digest 

username="Mufasa",  ← 客户端已知信息

realm="[email protected]",   ← 服务器端质询响应信息

nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",  ← 服务器端质询响应信息

uri="/dir/index.html", ← 客户端已知信息

qop=auth,   ← 服务器端质询响应信息

nc=00000001, ← 客户端计算出的信息

cnonce="0a4f113b", ← 客户端计算出的客户端nonce

response="6629fae49393a05397450978507c4ef1", ← 最终的摘要信息 ha3

opaque="5ccc069c403ebaf9f0171e9517f40e41"  ← 服务器端质询响应信息

     4. 如果认证成功,则返回相应的资源。如果认证失败,则仍返回401状态,要求重新进行认证。

    特记事项:

     1. 避免将密码作为明文在网络上传递,相对提高了HTTP认证的安全性。

     2. 当用户为某个realm首次设置密码时,服务器保存的是以用户名,realm,密码为基础计算出的哈希值(ha1),而非密码本身。

     3. 如果qop=auth-int,在计算ha2时,除了包括HTTP方法,URI路径外,还包括请求实体主体,从而防止PUT和POST请求表示被人篡改。

     4. 但是因为nonce本身可以被用来进行摘要认证,所以也无法确保认证后传递过来的数据的安全性。

   ※ nonce:随机字符串,每次返回401响应的时候都会返回一个不同的nonce。 

   ※ nounce:随机字符串,每个请求都得到一个不同的nounce。 

      ※ MD5(Message Digest algorithm 5,信息摘要算法)

         ① 用户名:realm:密码 ⇒ ha1

         ② HTTP方法:URI ⇒ ha2

         ③ ha1:nonce:nc:cnonce:qop:ha2 ⇒ ha3

◆ WSSE(WS-Security)认证  ← 扩展HTTP认证

   WSSE UsernameToken

    服务器端以nonce进行质询,客户端以用户名,密码,nonce,HTTP方法,请求的URI等信息为基础产生的response信息进行认证的方式。

    ※ 不包含密码的明文传递

    

    WSSE认证步骤:

     1. 客户端访问一个受WSSE认证保护的资源。

     2. 服务器返回401状态,要求客户端进行认证。

HTTP/1.1 401 Unauthorized

WWW-Authenticate: WSSE

realm="[email protected]",

profile="UsernameToken" ← 服务器期望你用UsernameToken规则生成回应

※ UsernameToken规则:客户端生成一个nonce,然后根据该nonce,密码和当前日时来算出哈希值。

     3. 客户端将生成一个nonce值,并以该nonce值,密码,当前日时为基础,算出哈希值返回给服务器。

Authorization: WSSE profile="UsernameToken"

X-WSSE:UsernameToken

username="Mufasa",

PasswordDigest="Z2Y......",

Nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",

Created="2010-01-01T09:00:00Z"

     4. 如果认证成功,则返回相应的资源。如果认证失败,则仍返回401状态,要求重新进行认证。

    特记事项:

     1. 避免将密码作为明文在网络上传递。

     2. 不需要在服务器端作设置。

     3. 服务器端必须保存密码本身,否则无法进行身份验证。

一. Basic 认证

  客户端以“ : ”连接用户名和密码后,再经BASE64加密通过Authorization请求头发送该密文至服务端进行验证,每次请求都需要重复发送该密文。可见Basic认证过程简单,安全性也低,存在泄露个人账号信息以及其他诸多安全问题。以下仅为原理演示,不代表真实情况:

  1. 客户端向服务器请求数据:

    GET / HTTP/1.1
    Host: www.myrealm.com

  2. 服务端向客户端发送验证请求401:

    HTTP/1.1 401 Unauthorised
    Server: bfe/1.0.8.18
    WWW-Authenticate: Basic realm="myrealm.com"
    Content-Type: text/html; charset=utf-8

  3. 客户端收到401返回值后,将自动弹出一个登录窗口,等待用户输入用户名和密码

  4. 将“用户名:密码”进行BASE64加密后发送服务端进行验证:

    GET / HTTP/1.1
    Host: www.myrealm.com
    Authorization: Basic xxxxxxxxxxxxxxxxxxxxxxxxxxxx

  5. 服务端取出Authorization请求头信息进行解密,并与用户数据库进行对比判断是否合法,合法将返回200 OK。RFC 2617 规格中Basic认证不发送Authentication-Info头部,Authentication-Info头部是Digest认证中新增的

 1 <?php 2   if (!isset($_SERVER[‘PHP_AUTH_USER‘])) { 3     header(‘WWW-Authenticate: Basic realm="My Realm"‘); 4     header(‘HTTP/1.0 401 Unauthorized‘); 5     echo ‘Text to send if user hits Cancel button‘; 6     exit; 7   } else { 8     echo "<p>Hello {$_SERVER[‘PHP_AUTH_USER‘]}.</p>"; 9     echo "<p>You entered {$_SERVER[‘PHP_AUTH_PW‘]} as your password.</p>";10   }

  

二. Digest 认证

  Digest认证试图解决Basic认证的诸多缺陷而设计,用户密码在整个认证过程中是个关键性要素。

  下为服务端发送的Digest认证响应头部实例及各指令含义说明:PHP官方文档中发送WWW-Authenticate头部时各指令之间用了空格,在Chrome下是不会弹出认证对话框的,应该换成”, “或”,“

WWW-Authenticate: Digest realm="Restricted area", qop="auth,auth-int", nonce="58e8e52922398", opaque="cdce8a5c95a1427d74df7acbf41c9ce0", algorithm="MD5"
  • WWW-Authenticate:服务端发送的认证质询头部

  • Authentication-Info:服务端发送的认证响应头部,包含nextnonce、rspauth响应摘要等

  • realm:授权域,至少应该包含主机名

  • domain:授权访问URIs列表,项与项之间以空格符分隔

  • qop:质量保护,值为auth或auth-int或[token],auth-int包含对实体主体做完整性校验

  • nonce:服务端产生的随机数,用于增加摘要生成的复杂性,从而增加破解密码的难度,防范“中间人”与“恶意服务器”等攻击类型,这是相对于不使用该指令而言的;另外,nonce本身可用于防止重放攻击,用于实现服务端对客户端的认证。RFC 2617 建议采用这个随机数计算公式:nonce = BASE64(time-stamp MD5(time-stamp “:” ETag “:” private-key)),服务端可以决定这种nonce时间有效性,ETag(URL对应的资源Entity Tag,在CGI编程中通常需要自行生成ETag和鉴别,可用于鉴别URL对应的资源是否改变,区分不同语言、Session、Cookie等)可以防止对已更新资源版本(未更新无效,故需要设定nonce有效期)的重放请求,private-key为服务端私有key

  • opaque:这是一个不透明的数据字符串,在盘问中发送给客户端,客户端会将这个数据字符串再发送回服务端器。如果需要在服务端和客户端之间维护一些状态,用nonce来维护状态数据是一种更容易也更安全的实现方式

  • stale:nonce过期标志,值为true或false

  • algorithm:摘要算法,值为MD5或MD5-sess或[token],默认为MD5

  下为客户端发送的Digest认证头请求部实例及各指令含义说明:

Authorization: Digest username="somename", realm="Restricted area", nonce="58e8e52922398", uri="/t.php", response="9c839dde909d270bc5b901c7f80f77d5", opaque="cdce8a5c95a1427d74df7acbf41c9ce0", qop="auth", nc=00000001, cnonce="9c30405c3a67a259"
  • cnonce:客户端产生的随机数,用于客户端对服务器的认证。由于“中间人”与“恶意服务器”等攻击方式的存在,导致一个特意选择而非随机唯一的nonce值传给客户端用于摘要的计算成为可能,使得“选择性明文攻击”可能奏效,最后用户密码泄露。因此与nonce一样,cnonce可用于增加摘要生成的复杂性,从而增加破解密码的难度,也就保证了对服务端的认证

    The countermeasure against this attack(选择明文攻击) is for clients to be configured to require the use of the optional "cnonce" directive;this allows the client to vary the input to the hash in a way not chosen by the attacker.
  • nc:当服务端开启qop时,客户端才需要发送nc(nonce-count)。服务端能够通过维护nc来检测用当前nonce标记的请求重放。如果相同的nc出现在用当前nonce标记的两次请求中,那么这两次请求即为重复请求。所以对于防止重放攻击而言,除了nonce之外,nc才是最后的保障。因此服务端除了维护用户账号信息之外,还需要维护nonce和nc的关联状态数据

  下面将就摘要计算方法进行说明: 

  1. 算法的一般性表示

    H(data) = MD5(data)
    KD(secret, data) = H(concat(secret, ":", data))
  2. 与安全信息相关的数据用A1表示,则

    a) 采用MD5算法:
        A1=(user):(realm):(password)
    b) 采用MD5-sess算法:
        A1=H((user):(realm):(password)):nonce:cnonce
  3. 与安全信息无关的数据用A2表示,则

    a) QoP为auth或未定义:
        A2=(request-method):(uri-directive-value)
    b) QoP为auth-int:
        A2=(request-method):(uri-directive-value):H((entity-body))
  4. 摘要值用response表示,则

    a) 若qop没有定义:
        response
        = KD(H(A1),<nonce>:H(A2))
        = H(H(A1),<nonce>:H(A2))
    b) 若qop为auth或auth-int:
        response
        = KD(H(A1),<nonce>:<nc>:<cnonce>:<qop>:H(A2))
        = H(H(A1),<nonce>:<nc>:<cnonce>:<qop>:H(A2))
    

三、Form Based Authentication 表单认证 
表单提交认证:认证信息作为请求参数,类似于Http基本认证

si. 安全风险

  • 在线字典攻击(Online dictionary attacks):攻击者可以尝试用包含口令的字典进行模拟计算response,然后与窃听到的任何nonce / response对进行对比,若结果一致则攻击成功。为应对针对弱口令的字典攻击,降低攻击成功的可能性,可以禁止用户使用弱口令

  • 中间人(Man in the Middle):在一次中间人攻击中,一个弱认证方案被添加并提供给客户端,因此你总是应该从多个备选认证方案中选择使用最强的那一个;甚至中间人可能以Basic认证替换掉服务端提供的Digest认证,从而窃取到用户的安全凭证,然后中间人可利用该凭证去响应服务端的Digest认证盘问;攻击者还可能打着免费缓存代理服务的幌子来招揽轻信者,通过实施中间人攻击,盗取他们的安全凭证;中间代理也可能诱导客户端来发送一个请求给服务端。为此,客户端可考虑给出安全等级风险警示,或在跟踪服务端的认证配置时发现其认证强度降低就发出警告,或配置成只使用强认证,或从指定站点来完成认证

  • 预先计算字典攻击(Precomputed dictionary attacks):攻击者先构建(response, password) 对字典,然后用选择性明文(nonce)攻击的办法来获得相应盘问的response,检索字典找到匹配的response则攻击成功

  • 批量式暴力攻击(Batch brute force attacks):中间人会对多个用户执行选择性明文攻击来搜集相应的responses,通过控制搜集的nonce / response对的数量将会缩短找到第一个password的耗时,这种攻击的应对之策就是要求客户端使用cnonce指令

  • 假冒服务器欺骗(Spoofing by Counterfeit Servers):对于Basic认证,这种攻击方式更容易奏效,对于Digest认证则更难,但前提是客户端必须知道将要使用的是Digest认证。用户在所使用的认证机制中如何发现这一潜在攻击样式应该得到可见的帮助

【参考资料】

1、HTTP常用认证方式 - 简书 https://www.jianshu.com/p/87a1322d325e

2、HTTP认证方式与https简介 -博客园 https://www.cnblogs.com/xzwblog/p/6834663.html

猜你喜欢

转载自blog.csdn.net/English0523/article/details/89468297