zoukankan      html  css  js  c++  java
  • HttpClient三种不同的服务器认证客户端方案

    http://blog.csdn.net/i_lovefish/article/details/9816783

    HttpClient三种不同的认证方案: Basic, Digest and NTLM. 这些方案可用于服务器或代理对客户端的认证,简称服务器认证或代理认证。

    服务器认证

      HttpClient处理服务器认证几乎是透明的,仅需要开发人员提供登录信息(login credentials)。登录信息保存在HttpState类的实例中,可以通过 setCredentials(String realm, Credentials cred)和getCredentials(String realm)来获取或设置。注意,设定对非特定站点访问所需要的登录信息,将realm参数置为null. HttpClient内建的自动认证,可以通过HttpMethod类的setDoAuthentication(boolean doAuthentication)方法关闭,而且这次关闭只影响HttpMethod当前的实例。

     

      抢先认证(Preemptive Authentication)可以通过下述方法打开.

     

      client.getState().setAuthenticationPreemptive(true);

     

      在这种模式时,HttpClient会主动将basic认证应答信息传给服务器,即使在某种情况下服务器可能返回认证失败的应答,这样做主要是为了减少连接的建立。为使每个新建的 HttpState实例都实行抢先认证,可以如下设置系统属性。

     

      setSystemProperty(Authenticator.PREEMPTIVE_PROPERTY, "true");

     

      Httpclient实现的抢先认证遵循rfc2617.

    代理认证

      除了登录信息需单独存放以外,代理认证与服务器认证几乎一致。用 setProxyCredentials(String realm, Credentials cred)和 getProxyCredentials(String realm)设、取登录信息。

     

      认证方案(authentication schemes)

     

      Basic

     

      是HTTP中规定最早的也是最兼容(?)的方案,遗憾的是也是最不安全的一个方案,因为它以明码传送用户名和密码。它要求一个UsernamePasswordCredentials实例,可以指定服务器端的访问空间或采用默认的登录信息。

     

      Digest

     

      是在HTTP1.1中增加的一个方案,虽然不如Basic得到的软件支持多,但还是有广泛的使用。Digest方案比Basic方案安全得多,因它根本就不通过网络传送实际的密码,传送的是利用这个密码对从服务器传来的一个随机数(nonce)的加密串。它要求一个UsernamePasswordCredentials实例,可以指定服务器端的访问空间或采用默认的登录信息。

    NTLM认证

      这是HttpClient支持的最复杂的认证协议。它M$设计的一个私有协议,没有公开的规范说明。一开始由于设计的缺陷,NTLM的安全性比Digest差,后来经过一个ServicePack补丁后,安全性则比较Digest高。NTLM需要一个NTCredentials实例. 注意,由于NTLM不使用访问空间(realms)的概念,HttpClient利用服务器的域名作访问空间的名字。还需要注意,提供给NTCredentials的用户名,不要用域名的前缀 - 如: "adrian" 是正确的,而 "DOMAINadrian" 则是错的.

     

      NTLM认证的工作机制与basic和digest有很大的差别。这些差别一般由HttpClient处理,但理解这些差别有助避免在使用NTLM认证时出现错误。

     

      从HttpClientAPI的角度来看,NTLM与其它认证方式一样的工作,差别是需要提供'NTCredentials'实例而不是'UsernamePasswordCredentials',对NTLM认证,访问空间是连接到的机器的域名,这对多域名主机会有一些麻烦.只有HttpClient连接中指定的域名才是认证用的域名。建议将realm设为null以使用默认的设置。

     

      NTLM只是认证了一个连接而不是一请求,所以每当一个新的连接建立就要进行一次认证,且在认证的过程中保持连接是非常重要的。 因此,NTLM不能同时用于代理认证和服务器认证,也不能用于http1.0连接或服务器不支持持久连接的情况。

    这是一个用于web浏览器或其他客户端在请求时提供用户名和密码的登录认证,要实现这个认证很简单:

    我们先来看下协议里面怎么定义这个认证的. 1. 编码: 将用户名 追加一个 冒号(':')接上密码,把得出的结果字符串在用Base64算法编码.

    1. 请求头: Authorization: 认证类型 编码字符串

    来看一下客户端如何发起请求例如,有一个用户名为:tom, 密码为:123456 怎么认证呢?

    步骤如下 1. 编码

    Base64('tom:123456') == dG9tOjEyMzQ1Ng==;

    1. 把编码结果放到请求头当中

      Authorization: Basic dG9tOjEyMzQ1Ng==

    请求样例客户端

    1
    2
    3
    GET / HTTP/1.1
    Host: localhost
    Authorization: Basic dG9tOjEyMzQ1Ng

    服务端应答

    1
    2
    3
    4
    HTTP/1.1 200 OK
    Date: Thu, 13 Jun 2013 20:25:37 GMT
    Content-Type: application/json; charset=utf-8
    Content-Length: 53

    如果没有认证信息

    1
    2
    3
    HTTP/1.1 401 Authorization Required
    Date: Thu, 13 Jun 2013 20:25:37 GMT
    WWW-Authenticate: Basic realm="Users"

    验证失败的时候,响应头加上WWW-Authenticate: Basic realm="请求域".

    这种http 基本实现,几乎目前所有浏览器都支持.不过,大家可以发现,直接把用户名和密码只是进行一次base64 编码实际上是很不安全的,因为对base64进行反编码十分容易,所以这种验证虽然简便,但是很少会在公开访问的互联网使用,一般多用在小的私有系统,例如,你们家里头的路由器,多用这种认证方式.

    这个认证可以看做是基本认证的增强版本,使用随机数+密码进行md5,防止通过直接的分析密码MD5防止破解. 摘要访问认证最初由 RFC 2069 (HTTP的一个扩展:摘要访问认证)中被定义加密步骤:

    1. ha1

    2. ha2 

    3. res

    后来发现,就算这样还是不安全(md5 可以用彩虹表进行攻击),所以在RFC 2617入了一系列安全增强的选项;“保护质量”(qop)、随机数计数器由客户端增加、以及客户生成的随机数。这些增强为了防止如选择明文攻击的密码分析。

    d1

    1. 如果 qop 值为“auth”或未指定,那么 HA2 为

      d3

    2. 如果 qop 值为“auth-int”,那么 HA2 为

      d3

    3. 如果 qop 值为“auth”或“auth-int”,那么如下计算 response:

      d4

    4. 如果 qop 未指定,那么如下计算 response:

      d5

    好了,知道加密步骤,下面我们用文字来描述一下;

    最后,我们的response 由三步计算所得. 1. 对用户名、认证域(realm)以及密码的合并值计算 MD5 哈希值,结果称为 HA1。

    HA1 = MD5( "tom:Hi!:123456" ) = d8ae91c6c50fabdac442ef8d6a68ae8c

    1. 对HTTP方法以及URI的摘要的合并值计算 MD5 哈希值,例如,"GET" 和 "/index.html",结果称为 HA2。

      HA2 = MD5( "GET:/" ) = 71998c64aea37ae77020c49c00f73fa8

    2. 最后生成的响应码

      Response = MD5("d8ae91c6c50fabdac442ef8d6a68ae8c:L4qfzASytyQJAC2B1Lvy2llPpj9R8Jd3:00000001:c2dc5b32ad69187a
      :auth:71998c64aea37ae77020c49c00f73fa8") = 2f22e6d56dabb168702b8bb2d4e72453;

    RFC2617 的安全增强的主要方式:

    发起请求的时候,服务器会生成一个密码随机数(nonce)(而这个随机数只有每次"401"相应后才会更新),为了防止攻击者可以简单的使用同样的认证信息发起老的请求,于是,在后续的请求中就有一个随机数计数器(cnonce),而且每次请求必须必前一次使用的打.这样,服务器每次生成新的随机数都会记录下来,计数器增加.在RESPONSE 码中我们可以看出计数器的值会导致不同的值,这样就可以拒绝掉任何错误的请求.

    请求样例(服务端 qop 设置为"auth")

    客户端 无认证

    1
    2
    GET / HTTP/1.1
    Host: localhost

    服务器响应(qop 为 'auth')

    1
    2
    3
    HTTP/1.1 401 Authorization Required
    Date: Thu, 13 Jun 2013 20:25:37 GMT
    WWW-Authenticate: Digest realm="Hi!", nonce="HSfb5dy15hKejXAbZ2VXjVbgNC8sC1Gq", qop="auth"

    客户端请求(用户名: "tom", 密码 "123456")

    1
    2
    3
    4
    5
    6
    7
    8
    9
    GET / HTTP/1.1
    Host: localhost
    Authorization: Digest username="tom",
                         realm="Hi!",
                         nonce="L4qfzASytyQJAC2B1Lvy2llPpj9R8Jd3",
                         uri="/",
                         qop=auth,
                         nc=00000001,
                         cnonce="c2dc5b32ad69187a",                     response="2f22e6d56dabb168702b8bb2d4e72453"

    服务端应答

    1
    2
    3
    4
    HTTP/1.1 200 OK
    Date: Thu, 13 Jun 2013 20:25:37 GMT
    Content-Type: application/json; charset=utf-8
    Content-Length: 53

    注意qop 设置的时候慎用:auth-int,因为一些常用浏览器和服务端并没有实现这个协议.

    http协议的认证模式
    http 的认证模式
      SIP类似Http协议。其认证模式也一样。Http协议(RFC 2616 )规定可以采用Base模式和摘要模式(Digest schema)。RFC 2617 专门对两种认证模式做了规定。RFC 1321 是MD5标准。Digest对现代密码破解来说并不强壮,但比基本模式还是好很多。MD5已经被山东大学教授找到方法可以仿冒(我的理解),但现在还在广泛使用。
    1.最简单的攻击方式
      如果网站要求认证,客户端发送明文的用户名密码,那网络上的窃听者可以轻而易举的获得用户名密码,起不到安全作用。我上学时曾在科大实验室局域网内窃听别人的科大BBS的密码,发现BBS的用户名密码居然是明文传输的。那种做贼的心虚和做贼的兴奋让人激动莫名。偷人钱财会受到道德谴责,偷人密码只会暗自得意忘形。比“窃书不算偷”还没有罪恶感。因此你的用户名和密码明文传输的话,无异将一块肥肉放在嘴馋的人面前。现在很多ASP网站的认证都将用户名和密码用MD5加密。MD5是将任意长度的字符串和128位的随机数字运算后生成一个16byte的加密字符串。因此窃听者抓住的是一团乱码。但是,这有一个问题:如果窃听者就用这团乱码去认证,还是可以认证通过。因为服务器将用户名密码MD5加密后得到的字符串就是那一团乱码,自然不能区别谁是合法用户。这叫重放攻击(replay attack)。这和HTTP的基本认证模式差不多。为了安全,不要让别人不劳而获,自然要做基本的防范。下面是Http协议规定的两种认证模式。
    2.基本认证模式
      客户向服务器发送请求,服务器返回401(未授权),要求认证。401消息的头里面带了挑战信息。realm用以区分要不同认证的部分。客户端收到401后,将用户名密码和挑战信息用BASE64加密形成证书,发送回服务器认证。语法如下:
          challenge   = "Basic" realm
          credentials = "Basic" basic-credentials
    示例:
       认证头: WWW-Authenticate: Basic realm="zhouhh@mydomain.com"
       证书:Authorization: Basic QsdfgWGHffuIcaNlc2FtZQ==
    3.摘要访问认证
      为了防止重放攻击,采用摘要访问认证。在客户发送请求后,收到一个401(未授权)消息,包含一个Challenge。消息里面有一个唯一的字符串:nonce,每次请求都不一样。客户将用户名密码和401消息返回的挑战一起加密后传给服务器。这样即使有窃听,他也无法通过每次认证,不能重放攻击。Http并不是一个安全的协议。其内容都是明文传输。因此不要指望Http有多安全。
    语法:
          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
    realm:让客户知道使用哪个用户名和密码的字符串。不同的领域可能密码不一样。至少告诉用户是什么主机做认证,他可能会提示用哪个用户名登录,类似一个Email。
    domain:一个URI列表,指示要保护的域。可能是一个列表。提示用户这些URI采用一样的认证。如果为空或忽略则为整个服务器。
    nonce:随机字符串,每次401都不一样。跟算法有关。算法类似Base64加密:time-stamp H(time-stamp ":" ETag ":" private-key) 。time-stamp为服务器时钟,ETag为请求的Etag头。private-key为服务器知道的一个值。
    opaque:服务器产生的由客户下去请求时原样返回。最好是Base64串或十六进制字符串。
    auth-param:为扩展用的,现阶段忽略。
    其他域请参考RFC2617。
    授权头语法:
           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"
    response:加密后的密码
    digest-uri:拷贝Request-Line,用于Proxy
    cnonce:如果qop设置,才设置,用于双向认证,防止攻击。
    nonce-count:如果服务器看到同样的计数,就是一次重放。
    示例:
    401响应:        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"
    4.比较基本认证和摘要访问认证都是很脆弱的。基本认证可以让窃听者直接获得用户名和密码,而摘要访问认证窃听者只能获得一次请求的文档。

  • 相关阅读:
    豆瓣api-简单跨域演示
    MVC4 验证用户登录一个特性搞定
    IIS7.5 不能加载外部引用的第三方JS,CSS,img等一系列静态文件
    三合一网站后台密码重置
    anaconda安装 (开源的Python发行版本)
    通达信指标函数说明大全
    织梦CMS如何修改中英文模板的当前位置
    微信小程序上架需要增值电信业务经营许可证ICP?
    PS抠图玻璃杯227
    PS用通道工具人物头发抠图246
  • 原文地址:https://www.cnblogs.com/shengs/p/4361299.html
Copyright © 2011-2022 走看看