中文rfc2617-001

2021-05-08  本文已影响0人  千转军师

时间:2021年5月8日16:01:25

HTTP Authentication: Basic and Digest Access Authentication

A、摘要

B、目录

1访问认证 ................................ 3.
1.1依赖HTTP / 1.1规范 ............ 3.
1.2访问认证框架 ................... 3.
2基本身份验证方案 .......................... 5
3消化访问身份验证方案 .................. 6
3.1介绍 ...................................... 6
3.1.1目的 ......................................... 6
3.1.2整体操作 ............................... 6
3.1.3消化值的表示 ................. 7
3.1.4局限性 ..................................... 7
3.2规范的消化头 ................... 7
3.2.1 WWW-Authenticate响应头 ............ 8
3.2.2授权请求头 ................ 11
3.2.3 Authentication-Info头 .................. 15
3.3消化操作 .................................. 17
3.4安全协议谈判 ..................... 18
3.5的例子 ........................................... 18
3.6代理认证代理授权......19
4安全注意事项 .............................. 19
4.1使用Basic进行客户端认证
身份验证 .................................... 19
4.2使用Digest对客户端进行认证
身份验证 .................................... 20.
4.3有限使用现时标志值 .......................... 21
4.4 Digest与Basic Authentication的比较....22
4.5重播攻击 .................................... 22
4.6多重认证产生的弱点
计划 ........................................... 23
4.7在线词典攻击 ......................... 23
4.8的人中间 ................................. 24
4.9选择明文攻击 .......................... 24
4.10预先计算的字典攻击 .................... 25
4.11批蛮力攻击 ......................... 25
4.12由假冒欺骗服务器 ................... 25
4.13存储密码 ................................. 26
4.14总结 ........................................... 26
5样例实现 ................................ 27
6致谢 ...................................... 31
7参考 ........................................... 31
8作者的地址 ................................... 32
9完整的版权声明 ............................. 34

1、访问认证

1.1 对HTTP/1.1规范的依赖

该规范是HTTP/1.1规范[2]的配套版本。它使用该文档的扩充的BNF第2.1节,并依赖于该文件中定义的非终结符和其他方面HTTP / 1.1规范。

1.2 接入认证框架

HTTP提供了一种简单的询问-响应身份验证机制,该机制用于服务器询问客户端请求以及客户端提供身份验证信息。它使用可扩的不区分大小写的 token(标志) 来标确定认证方法。以下的逗号分隔的属性-数值列表,该列表带有达到认证的所需参数,可以通过该方式实现。

auth-scheme    = token
auth-param     = token "=" ( token | quoted-string )
challenge   = auth-scheme 1*SP 1#auth-param
realm       = "realm" "=" realm-value
realm-value = quoted-string

realm(领域)

credentials = auth-scheme #auth-param

2、基础的认证方案

  challenge   = "Basic" realm
  credentials = "Basic" basic-credentials

控件内的URI的未授权请求保护空间,带有挑战的源服务器的响应可能与以下几点一样:

WWW-Authenticate: Basic realm="WallyWorld"
basic-credentials = base64-user-pass
      base64-user-pass  = <base64 [4] encoding of user-pass,except not limited to 76 char/line>
      user-pass   = userid ":" password
      userid      = *<TEXT excluding ":">
      password    = *TEXT
 Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

3、摘要访问认证方案

3.1 介绍

3.1.1 目的

3.1.2 完整的操作

3.1.3 摘要值的表示

3.1.4 局限性

3.2 对摘要头部的指定

challenge        =  "Digest" digest-challenge

digest-challenge  = 1#( realm | [ domain ] | nonce |
                      [ opaque ] |[ stale ] | [ algorithm ] |
                      [ qop-options ] | [auth-param] )


domain            = "domain" "=" <"> URI ( 1*SP URI ) <">
URI               = absoluteURI | abs_path
nonce             = "nonce" "=" nonce-value
nonce-value       = quoted-string
opaque            = "opaque" "=" quoted-string
stale             = "stale" "=" ( "true" | "false" )
algorithm         = "algorithm" "=" ( "MD5" | "MD5-sess" |
                   token )
qop-options       = "qop" "=" <"> 1#qop-value <">
qop-value         = "auth" | "auth-int" | token

上面使用的指令的值的含义是如下:

time-stamp H(time-stamp ":" ETag ":" private-key)

其中,时间戳是服务器生成的时间或其他非重复的值,ETag是与请求实体相关联的HTTP ETag头的值,私有密钥是只有服务器知道的数据。
使用这种形式的nonce,服务器将在接收到客户端身份验证报头后重新计算散列部分,如果与报头中的nonce不匹配,或者时间戳值不够新,则拒绝请求。
这样服务器就可以限制nonce的有效时间。
包含ETag可以防止重放对资源更新版本的请求。
(注意:在nonce中包含客户机的IP地址似乎可以为服务器提供限制nonce重用到最初获得它的同一客户机的能力。
然而,这将破坏代理场,在代理场中,来自单个用户的请求通常要通过不同的代理。
此外,IP地址欺骗也不是那么难。)
实现可能选择不接受以前使用过的
Nonce或以前使用的摘要,以防止
重放攻击。或者,实现可能选择使用一次性
用于POST或PUT请求的nonces或摘要,以及用于GET的时间戳请求。有关所涉及问题的更多细节,请参见此文档第4节。
nonce对客户端是不透明的。

H(data) = MD5(data)

KD(secret, data) = H(concat(secret, ":", data))

即,摘要是由冒号连接的秘密的MD5
与数据连接。“MD5-sess”算法的目的是
允许高效的第三方认证服务器;为使用差异,请参见3.2.2.2。

3.2.2 (Authorization Request)认证请求头部

预计客户端将重试请求,并传递一个授权标题行,根据上面的框架定义,利用如下。

credentials      = "Digest" digest-response
       digest-response  = 1#( username | realm | nonce | digest-uri
                       | response | [ algorithm ] | [cnonce] |
                       [opaque] | [message-qop] |
                           [nonce-count]  | [auth-param] )

       username         = "username" "=" username-value
       username-value   = quoted-string
       digest-uri       = "uri" "=" digest-uri-value
       digest-uri-value = request-uri   ; As specified by HTTP/1.1
       message-qop      = "qop" "=" qop-value
       cnonce           = "cnonce" "=" cnonce-value
       cnonce-value     = nonce-value
       nonce-count      = "nc" "=" nc-value
       nc-value         = 8LHEX
       response         = "response" "=" request-digest
       request-digest = <"> 32LHEX <">
       LHEX             =  "0" | "1" | "2" | "3" |
                           "4" | "5" | "6" | "7" |
                           "8" | "9" | "a" | "b" |
                           "c" | "d" | "e" | "f"

opaque字段和algorithm字段的值必须是所提供的值在实体的WWW-Authenticate响应头中要求。

3.2.2.1 请求摘要

request-digest  = <"> < KD ( H(A1),     unq(nonce-value)
                                          ":" nc-value
                                          ":" unq(cnonce-value)
                                          ":" unq(qop-value)
                                          ":" H(A2)
                                  ) <">

如果"qop"指令不存在(此构造是为了兼容RFC 2069)

request-digest  =
                 <"> < KD ( H(A1), unq(nonce-value) ":" H(A2) ) >
   <">

下面是A1和A2的定义。

3.2.2.2 A1

如果“算法”指令的值是“MD5”或未指定,则
A1是:

A1       = unq(username-value) ":" unq(realm-value) ":" passwd

地方

passwd   = < user's password >

如果“algorithm”指令的值为“MD5-sess”,则A1为
只计算一次-在第一个请求后的客户端
从服务器接收到WWW-Authenticate挑战。它使用服务器nonce从该挑战,和第一个客户端nonce值
构建A1如下:

 A1       = H( unq(username-value) ":" unq(realm-value)
                     ":" passwd )
                     ":" unq(nonce-value) ":" unq(cnonce-value)

3.2.2.3 A2

如果"qop"指令的值是"auth"或未指定,则A2
是:

 A2       = Method ":" digest-uri-value

如果qop值为auth-int,则A2为:

A2       = Method ":" digest-uri-value ":" H(entity-body)

指令值和带引号的字符串

username="Mufasa", realm=myhost@testrealm.com
Mufasa:myhost@testrealm.com:Circle Of Life

3.2.2.5 各种注意事项

3.2.3 (Authentication-Info)认证信息头部

Authentication-Info头被服务器用于通信
控件中有关成功身份验证的一些信息
响应。

 AuthenticationInfo = "Authentication-Info" ":" auth-info
        auth-info          = 1#(nextnonce | [ message-qop ]
                               | [ response-auth ] | [ cnonce ]
                               | [nonce-count] )
        nextnonce          = "nextnonce" "=" nonce-value
        response-auth      = "rspauth" "=" response-digest
        response-digest    = <"> *LHEX <">
  A2       = ":" digest-uri-value

如果 "qop=auth-int",那么

  A2       = ":" digest-uri-value ":" H(entity-body)

3.3 摘要操作

3.4 安全协议通过

3.5 例子

 HTTP/1.1 401 Unauthorized
         WWW-Authenticate: Digest
                 realm="testrealm@host.com",
                 qop="auth,auth-int",
                 nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",
                 opaque="5ccc069c403ebaf9f0171e9517f40e41"
Authorization: Digest username="Mufasa",
                 realm="testrealm@host.com",
                 nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",
                 uri="/dir/index.html",
                 qop=auth,
                 nc=00000001,
                 cnonce="0a4f113b",
                 response="6629fae49393a05397450978507c4ef1",
                 opaque="5ccc069c403ebaf9f0171e9517f40e41"

3.6 Proxy-Authentication(证明) 和 Proxy-Authorization(授权)

安全注意事项

4.1使用基本身份验证的客户端身份验证

4.4 摘要与基本认证的比较

4.5 重复攻击

4.6 多个认证方案产生的缺陷

4.7 在线字典攻击

4.8 中间人攻击

4.9 可选的明文攻击

4.10 预估字典攻击

4.11 批量暴力破解攻击

4.12 仿冒服务器欺骗

4.13 储存密码

4.14 总结

5、样本实现

下面的代码实现了H(A1)、H(A2)、请求摘要和响应摘要的计算,以及一个计算3.5节示例中使用的值的测试程序。
它使用RFC 1321的MD5实现。
文件 “digcacl.h”

#define HASHLEN 16
typedef char HASH[HASHLEN];
#define HASHHEXLEN 32
typedef char HASHHEX[HASHHEXLEN+1];
#define IN
#define OUT

/* calculate H(A1) as per HTTP Digest spec */
void DigestCalcHA1(
    IN char * pszAlg,
    IN char * pszUserName,
    IN char * pszRealm,
    IN char * pszPassword,
    IN char * pszNonce,
    IN char * pszCNonce,
    OUT HASHHEX SessionKey
    );

/* calculate request-digest/response-digest as per HTTP Digest spec */
void DigestCalcResponse(
    IN HASHHEX HA1,           /* H(A1) */
    IN char * pszNonce,       /* nonce from server */
    IN char * pszNonceCount,  /* 8 hex digits */
    IN char * pszCNonce,      /* client nonce */
    IN char * pszQop,         /* qop-value: "", "auth", "auth-int" */
    IN char * pszMethod,      /* method from the request */
    IN char * pszDigestUri,   /* requested URL */
    IN HASHHEX HEntity,       /* H(entity body) if qop="auth-int" */
    OUT HASHHEX Response      /* request-digest or response-digest */
    );

文件 "digcacl.c"

#include <global.h>
#include <md5.h>
#include <string.h>
#include "digcalc.h"

void CvtHex(
    IN HASH Bin,
    OUT HASHHEX Hex
    )
{
    unsigned short i;
    unsigned char j;

    for (i = 0; i < HASHLEN; i++) {
        j = (Bin[i] >> 4) & 0xf;
        if (j <= 9)
            Hex[i*2] = (j + '0');
         else
            Hex[i*2] = (j + 'a' - 10);
        j = Bin[i] & 0xf;
        if (j <= 9)
            Hex[i*2+1] = (j + '0');
         else
            Hex[i*2+1] = (j + 'a' - 10);
    };
    Hex[HASHHEXLEN] = '\0';
};

/* calculate H(A1) as per spec */
void DigestCalcHA1(
    IN char * pszAlg,
    IN char * pszUserName,
    IN char * pszRealm,
    IN char * pszPassword,
    IN char * pszNonce,
    IN char * pszCNonce,
    OUT HASHHEX SessionKey
    )
{
      MD5_CTX Md5Ctx;
      HASH HA1;

      MD5Init(&Md5Ctx);
      MD5Update(&Md5Ctx, pszUserName, strlen(pszUserName));
      MD5Update(&Md5Ctx, ":", 1);
      MD5Update(&Md5Ctx, pszRealm, strlen(pszRealm));
      MD5Update(&Md5Ctx, ":", 1);
      MD5Update(&Md5Ctx, pszPassword, strlen(pszPassword));
      MD5Final(HA1, &Md5Ctx);
      if (stricmp(pszAlg, "md5-sess") == 0) {
 MD5Init(&Md5Ctx);
            MD5Update(&Md5Ctx, HA1, HASHLEN);
            MD5Update(&Md5Ctx, ":", 1);
            MD5Update(&Md5Ctx, pszNonce, strlen(pszNonce));
            MD5Update(&Md5Ctx, ":", 1);
            MD5Update(&Md5Ctx, pszCNonce, strlen(pszCNonce));
            MD5Final(HA1, &Md5Ctx);
      };
      CvtHex(HA1, SessionKey);
};

/* calculate request-digest/response-digest as per HTTP Digest spec */
void DigestCalcResponse(
    IN HASHHEX HA1,           /* H(A1) */
    IN char * pszNonce,       /* nonce from server */
    IN char * pszNonceCount,  /* 8 hex digits */
    IN char * pszCNonce,      /* client nonce */
    IN char * pszQop,         /* qop-value: "", "auth", "auth-int" */
    IN char * pszMethod,      /* method from the request */
    IN char * pszDigestUri,   /* requested URL */
    IN HASHHEX HEntity,       /* H(entity body) if qop="auth-int" */
    OUT HASHHEX Response      /* request-digest or response-digest */
    )
{
      MD5_CTX Md5Ctx;
      HASH HA2;
      HASH RespHash;
       HASHHEX HA2Hex;

      // calculate H(A2)
      MD5Init(&Md5Ctx);
      MD5Update(&Md5Ctx, pszMethod, strlen(pszMethod));
      MD5Update(&Md5Ctx, ":", 1);
      MD5Update(&Md5Ctx, pszDigestUri, strlen(pszDigestUri));
      if (stricmp(pszQop, "auth-int") == 0) {
            MD5Update(&Md5Ctx, ":", 1);
            MD5Update(&Md5Ctx, HEntity, HASHHEXLEN);
      };
      MD5Final(HA2, &Md5Ctx);
       CvtHex(HA2, HA2Hex);

      // calculate response
      MD5Init(&Md5Ctx);
      MD5Update(&Md5Ctx, HA1, HASHHEXLEN);
      MD5Update(&Md5Ctx, ":", 1);
      MD5Update(&Md5Ctx, pszNonce, strlen(pszNonce));
      MD5Update(&Md5Ctx, ":", 1);
      if (*pszQop) {
MD5Update(&Md5Ctx, pszNonceCount, strlen(pszNonceCount));
          MD5Update(&Md5Ctx, ":", 1);
          MD5Update(&Md5Ctx, pszCNonce, strlen(pszCNonce));
          MD5Update(&Md5Ctx, ":", 1);
          MD5Update(&Md5Ctx, pszQop, strlen(pszQop));
          MD5Update(&Md5Ctx, ":", 1);
      };
      MD5Update(&Md5Ctx, HA2Hex, HASHHEXLEN);
      MD5Final(RespHash, &Md5Ctx);
      CvtHex(RespHash, Response);
};

文件 “digtest.c”

#include <stdio.h>
#include "digcalc.h"

void main(int argc, char ** argv) {

      char * pszNonce = "dcd98b7102dd2f0e8b11d0f600bfb0c093";
      char * pszCNonce = "0a4f113b";
      char * pszUser = "Mufasa";
      char * pszRealm = "testrealm@host.com";
      char * pszPass = "Circle Of Life";
      char * pszAlg = "md5";
      char szNonceCount[9] = "00000001";
      char * pszMethod = "GET";
      char * pszQop = "auth";
      char * pszURI = "/dir/index.html";
      HASHHEX HA1;
      HASHHEX HA2 = "";
      HASHHEX Response;

      DigestCalcHA1(pszAlg, pszUser, pszRealm, pszPass, pszNonce,
pszCNonce, HA1);
      DigestCalcResponse(HA1, pszNonce, szNonceCount, pszCNonce, pszQop,
       pszMethod, pszURI, HA2, Response);
      printf("Response = %s\n", Response);
};

==================>略

6 鸣谢

7 参考

8 作者地址

上一篇下一篇

猜你喜欢

热点阅读