HTTP基本认证(basic authentication)就是简单的质询/回应 (challenge/response)
试图访问一个受基本认证保护的资源时,没有提供正确的证书,那么会收到服务器对你身份的质询,然后必须重新发出请求。
例如 客户端 发送一个没有给出证书的请求
GET /xxxx.html HTTP/1.1
Host: www.example.com
服务器的响应会如下:
401 Unauthorized
WWW-Authrnticate: Basic realm='my private Data'
(这里指出了应该采用的认证方案 基本认证,还指定了realm,通常用于标识网站上的一组资源,可以是任意名称。认证类型表明采用哪种认证方案 如‘Basic’,而realm 表明对什么‘my private Date’ 进行认证)
客户端需要以用户名和密码来回应基本认证的质询。用户名和密码信息也许已经保存在属于该realm的缓冲了,假如没有的话客户端将提示最终用户输入。客户端获得用户名和密码后,会把这两则信息转换为一个采用base64编码的字符串。许多编程语言都提供了用于进行base64位编码的标准库。这个看似由随机字符组成的字符串就是Authorization报头的值
基本认证实际上是用明文来传递用户名密码的,解决办法就是采用HTTPS
这儿的证书:可以是一个用户名/密码。也可以是一个API key,或者一个认证令牌
摘要认证
摘要认证是另一种防止证书被窃听的办法,它能确保在非加密的HTTP上传输证书的安全,摘要认证的基本模式跟基本认证一样,即客户端发出请求后,得到服务器返回的质询。
如:
401 Unauthorized
WWW-Authenticate:Digest realm="My private data",qop="auth",nonce="0cc175sjdhs7866s767sa8sdds77",opaque="98e887ff8sdc00889v"
这里WWW-Authenticate报头指出认证类型是摘要认证(“Digest”)。另外还包含了3则其他信息。nonce:随机字符串,每个请求的nonce值都不相同。
客户端的任务是把这则信息转换为一个加密的字符串,以证明客户端知道正确的密码。但该字符串并不包含实际的密码。
客户端首先生成一个客户端nonce和一个序号。
然后,客户端根据以下信息构造一个“摘要”字符串:
请求里的HTTP方法
URI路径
质询响应里的四则信息
以及用户名、密码、客户端nonce、序号。
摘要认证构造摘要字符串的过程,要比基本认证构造base64字符串复杂的多
为HTTP摘要认证构造摘要字符串的例子(ruby):
1 #原请求里的信息 2 3 METHOD="GET" 4 5 PATH="/resource.html" 6 7 #质询响应里的信息 8 9 REALM=“My private data” 10 11 NONCE="0cc175sjdhs7866s767sa8sdds77" 12 13 OPAQUE="98e887ff8sdc00889v" 14 15 QOP="auth" 16 17 #客户端已知或计算出的信息 18 19 NC="00000001" (请求计数器) 20 21 CNONCE='4a9a08df00f0e00b87676' (客户码随机数) 22 23 USER='Alibaba' 24 25 PASSWORD='opens sesame' 26 27 #计算最终的摘要的三个步骤 28 29 ha1=MD5::hexdigest("#{USER}:#{REALM}:#{PASSWORD}") 30 31 ha2=MD5::hexdigest("#{METHOD}:#{PATH}") 32 33 ha3=MD5::hexdigest("#{ha1}:#{NONCE}:#{NC}:#{CNONCE}:#{QOP}:#{ha2}") 34 35 puts ha3
算出摘要字符串之后,客户端就可以重新发送请求,并把所有常量(除了密码)及摘要字符串传回给服务器了:
虽然摘要认证比较复杂,但其流程跟基本认证是一样的:请求、质询、回应。摘要认证更基本认证的关键不同在于:即便是服务器,页无法根据摘要获知你确切的密码。当用户为某个realm首次设置密码时,服务器需要为user:realm:password计算哈希值(上面的ha1),然后记录下来。当服务器需要进行身份验证时,可以直接利用这个值计算出最终的ha3,而不必再需要用户名和密码。
另一个区别在于,客户端的每个请求,实际上对应着两次请求,第一次请求的目的是获得质询响应。这次请求不包含认证信息,并且该请求得到的响应总具有响应代码401,但该响应的WWW-Authenticate报头里包含一个唯一的nonce,客户端需要用这个nonce值来构造正确的Authorization报头。接着,客户端发出第二次请求,这次请求里包含Authorization报头,应该会成功。
摘要认证中把qop=auth-int改成qop=auth表明:在计算ha2时,除了要包括HTTP方法和URI路径以外,还要包括请求实体主体--这可以防止PUT和POST请求的表示被某个中间人篡改