HTTP认证及其在Web平台中的实现.doc_第1页
HTTP认证及其在Web平台中的实现.doc_第2页
HTTP认证及其在Web平台中的实现.doc_第3页
HTTP认证及其在Web平台中的实现.doc_第4页
HTTP认证及其在Web平台中的实现.doc_第5页
已阅读5页,还剩1页未读, 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

HTTP认证及其在Web平台中的实现一、前言 HTTP认证是Web服务器对客户端的权限进行认证的一种方式,能够为Web应用提供一定程度的安全保障。目前一些Web应用项目已经提出了采用HTTP认证的需求。虽然一般的Web容器都提供基本认证和摘要认证的API,但不同的Web容器提供的API也互不相同,因此我们在ZX Web平台的工具包中提供了一组API,利用这组API,开发人员可以在应用程序中使用统一的接口轻松实现HTTP认证功能,而不必依赖于Web容器。二、HTTP认证机制 HTTP认证采用“质询-响应(challenge-response)”的机制。“质询”是服务器端对客户端的质询,即要求客户端发送认证信息;“响应”是客户端对“质询”的响应,即发送带有认证信息的HTTP请求。 一般来说,客户端第一次请求一个URI时,并不知道是否需要认证,因此总是不带认证信息的,这时服务器端就会找不到认证信息,认证失败,于是向客户端发出一个“质询”。 所谓“发出质询”,就是给客户端发送一个HTTP响应,其状态码为401 (Unauthorized),并且包含消息头WWW-Authenticate,客户端看到这个响应就知道这个URI需要认证。WWW-Authenticate消息头格式为 WWW-Authenticate:challenge 其中是就是质询信息,RFC2617中的定义为:challenge = auth-scheme 1*SP 1#auth-paramauth-scheme = tokenauth-param = token = ( token | quoted-string ) 在challenge的定义中,首先是auth-scheme,即认证方案,它被定义为一个token,即预定义的符号。所谓token,就是一些字符串,但这些字符串不是随意的,而是大家约定的,它们具有特定的含义。auth-scheme的取值只能是Basic或Digest,分别表示基本认证和摘要认证,这两个单词就是token。这里没有把auth-scheme定义为Basic|Digest,而是一个token,说明还可以进行扩展,还可以取其他符号只要服务器端和客户端互相约定都能理解就行。 接着,“1*SP”表示1个或多个空格符。其中“1*”表示数量为1个到多个,“SP”即空格符(ASCII码32)。 然后是“1#auth-param”,表示一个auth-param的列表。其中的“1#”也表示后面的元素是1到多个,但与“1*”不同的是,“1#”表示一个“列表”,即元素之间是用逗号“,”分隔开的。列表中的每个auth-param被定义为一个名值对,即 符号=符号 或 符号=“引号中的字符串” 这两种形式。 基本认证和摘要认证中都定义了一个相同的auth-param,即realm,定义为: realm = “realm”“=” realm-value realm-value = quoted-stringrealm-value是一个两端加引号的大小写相关的字符串,表示要求认证的“领域(realm)”。领域是由服务器自己决定的,不同的服务器可以设置自己的领域,同一个服务器也可以有多个领域。质询中包含领域信息是为了让客户端知道哪个范围的用户名是合法的,RFC2617中建议领域至少包含主机名和有权限的用户组,例如“registered_”。 客户端收到质询后,应该给服务器端返回一个“响应”,即重新发送一个新的HTTP请求。这个新的HTTP请求与前一个HTTP请求的差别在于多了一个Authorization消息头,该消息头的格式为Authorization:credentials,其中的credentials就是认证信息,认证信息的格式根据不同的认证方案而有所不同。 服务器端对认证信息进行判断,只有认证通过,才会响应客户端的请求。 1. 基本认证 基本认证的质询中只定义了一种auth-param,即realm,因此基本认证的质询也定义为challenge = “Basic” realm质询举例: 当服务器端认证不通过,将返回一个状态码为401(Unautherized)的响应消息,并带有如下消息头: WWW-Authenticate: Basic realm=“My Secret World” 基本认证的认证信息credentials定义为: credentials = “Basic” basic-credentials basic-credentials = base-user-pass base-user-pass = user-pass = userid “:” password userid = * password = *TEXT 简单说,认证信息就是“Basic”后面加上“:”的Base编码,只不过这里的Base编码不对每一行的字符数做最大76个的限制。 认证信息举例: 如果用户名为“abc”,密码为“abcd”,将“abc:abcd”进行Base编码得到“YWJjOmFiY2Q=”,于是消息头中认证信息为Authorization: Basic YWJjOmFiY2Q= 2. 摘要认证 由于基本认证被认为是不安全的认证方式,摘要认证作为替代方案被制定了出来。摘要认证中,用户名和密码不会以明文方式传送,而是经过了加密。从名称可以看出,是生成了信息摘要,客户端和服务器使用各自的密码以同样的算法生成信息摘要,两者比较即可判断客户端的密码是否正确。 摘要认证仍然采用WWW-Authenticate和Authorization两个消息头,另外还规定了消息头Authentication-Info。消息头Authentication-Info用于认证通过之后,服务器给客户端返回一些信息,例如可以用来指定下一次认证用的临时值,或者也生成一个摘要,表明服务器确实知道用户密码,等等。不过这个消息头并不是必须的,实际应用中一般也用不着,因此Web平台中目前没有实现,这里也不做介绍,若有兴趣请查看RFC2617。三、HTTP认证的安全性 1. 基本认证的安全性 基本认证不是一种安全的认证方式,因为Base编码仅仅是编码,而不是加密,以这种形式在互联网上传递用户名和密码,其危险性是显而易见的。但如果对安全性要求不高,则可以使用这种认证方式做为最简单的安全措施-毕竟比没有安全措施要好。 当然,如果能够保证中间不会有人截取数据包,例如处于内部局域网,或者底层协议是安全的(如使用SSL或其他一些安全机制),倒是可以弥补HTTP基本认证在安全性方面的不足。 2. 摘要认证的安全性 由于基本认证过于危险,人们才使用摘要认证作为一种替代方案。但它也仅仅是作为基本认证的替代品,因为它本身也不是十分安全的,也存在一些弱点。 (1)摘要认证只能作为权限认证机制,并非保密措施,因为消息体并没有被加密。qop使用“auth-int”只能保证消息体不被修改,不能防止被偷看。 (2)Replay攻击:攻击者可能截取一次摘要信息,然后利用相同的摘要信息请求相同的URI,如果该URI可以通过POST或PUT方法访问,则攻击者可能修改消息体。控制nonce中的时间戳和nc次数有助于减小replay攻击机会;每次使用新的nonce值(用Authentication-Info消息头)可避免遭受replay攻击,当然也增加了开销。 (3)MITM(Man in the Middle)攻击:攻击者截取网络数据包,给客户端发送一个假的质询,只要求客户端使用基本认证,从而取得密码。MITM最常见的方式是提供一个“免费”的但其实是恶意的代理服务器。要防止此类攻击,可双方约定只使用摘要认证,不允许使用基本认证,但一般浏览器并不支持指定认证方式,除非是自己开发的客户端。 其他还有些攻击方式,例如通过“查字典”猜密码等比较野蛮的方式。虽然摘要认证有这些弱点,但在许多情况下还是有它的使用价值的,至少比基本认证是好多了。四、HTTP认证在ZX Web平台中的实现 在ZX Web平台的包中提供了HTTP认证的API,这组API包括一个接口HttpAuth以及该接口的两个实现类HttpBasicAuth和HttpDigestAuth,分别实现基本认证和摘要认证。开发人员可以使用接口,也可以直接使用两个实现类。类图如图1所示。 1. HttpAuth接口 这个接口应该提供一个方法取得用户提交的用户名和密码,以便应用程序校验其正确性。在基本认证中,这一点是可以做到的,但在摘要认证中服务器端并不能知道客户端提交的密码,所能得到的只是对包含密码的数据进行MD5编码所得到一个摘要,因此为了照顾摘要认证,HttpAuth接口没有设计这样一个方法,而是提供另一个方法authenticate,调用者将用户名和正确的密码作为该方法的参数传入,返回认证结果。该方法还需要另一个参数,即HTTP请求HttpServletRequest的一个实例,因为需要从中取得用户提交的认证信息;HttpAuth接口的所有方法都需要这个参数。 在大多数情况下,合法的用户不止一个,因此调用authenticate方法之前必须知道客户端提交的用户名。HttpAuth接口的getUserName方法完成此功能。这两个方法描述如下: getUserName 功能: 取得用户发来的认证信息中的用户名。原型: public String getUserName(HttpServletRequest req)参数: req - HTTP请求 返回: 返回认证信息中的用户名。若未取到(请求中未包含认证信息或认证信息格式不正确),返回null。 authenticate 功能: 判断一个HTTP请求的认证信息中用户名和密码是否与指定的相符。原型: public boolean authenticate(HttpServletRequest req, String userName, String password)参数: req - HTTP请求 userName - 指定的用户名 password - 指定的密码 返回: true - 认证通过 false - 认证未通过 当调用authenticate方法发现认证未通过,应该给客户端发回一个质询,即设置响应的状态码为401,并设置消息头WWW-Authenticate。HttpAuth接口的setUnauth方法负责完成此功能。SetUnauth 功能: 设置 401 Unauthorized 状态码,并添加WWW-Authenticate消息头。 原型: public void setUnauth(HttpServletRequest req, HttpServletResponse rsp, String realm) 参数: req - HTTP请求 rsp - HTTP响应 realm - WWW-Authenticate消息头中的realm值。若为null,则默认使用 servername:port 返回:无setUnauth方法设置HTTP响应对象rsp的状态码为401,并添加WWW-Authenticate消息头,至于消息头的内容,HttpBasicAuth类和HttpDigestAuth类根据基本认证和摘要认证的规范不同而有不同的实现。设置WWW-Authenticate消息头需要realm值,调用者通过realm参数指定realm值。调用者如果不想指定realm值,可以置realm参数为null,或直接调用另一种参数形式的setUnauth方法: public void setUnauth(HttpServletRequest req, HttpServletResponse rsp) 如果不指定realm值,setUnauth方法将从请求对象req中取得服务器名和端口,按servername:port组合,以此作为realm的值。最后,HttpAuth接口提供getAuth方法,以取得HTTP请求中用户提交的认证信息,即Authorization消息头中Basic或Digest标志之后的信息;若是基本认证,此字符串是BASE编码的,则返回解码后的字符串。对开发人员来说,此方法不是必须的,但可以用于调试。getAuth 功能: 取得用户提交的认证信息。 原型: public String getAuth(HttpServletRequest req) 参数: req - HTTP请求 返回: 用户提交的摘要认证信息中Digest或Basic标识之后信息;若是BASE编码,返回解码后的字符串。 2. HttpBasicAuth类 HttpBasicAuth类实现HTTP基本认证。 HttpBasicAuth除了实现HttpAuth接口的所有方法外,还增加一个方法getUserNamePwd,用以取得客户端提交的用户名和密码。在某些情况下,服务器端的数据库或文件中并没有保存用户密码的明文,而是保存对密码经过某种不可逆加密算法(MD5或其他)而得到的信息摘要(如UNIX系统)。如果是这样,服务器端无法调用authenticate方法来进行认证,只能先调用getUserNamePwd方法取得HTTP请求中的用户名和密码,然后按照数据库或文件中的相同加密算法计算其摘要,最后比较所得到的摘要是否与数据库或文件中的相同。这种情况下不能使用摘要认证,只能使用基本认证。 getUserNamePwd 功能: 取得用户名密码字符串数组。原型: public String getUserNamePwd(HttpServletRequest req)参数: req - HTTP请求 返回: 字符串数组,第一个元素为用户名,第二个元素为密码;若未取到用户名和密码,返回null。 HttpBasicAuth只有一个成员变量: protected static BASEDecoder baseDecoder = new BASEDecoder();即sun.misc.BASEDecoder类的一个实例,用于BASE解码。 3. HttpDigestAuth类 HttpDigestAuth类实现HTTP摘要认证。HttpDigestAuth类除了实现HttpAuth接口外,根据摘要认证的特点,还提供了其他一些方法。 客户端提交的认证信息中,有一个nc值,表示临时值nonce已被使用的次数;HttpDigestAuth类的方法getNonceCount可取得此值。 getNonceCount 功能: 取得用户发来的认证信息中的nc(NonceCount)值。原型: public int getNonceCount(HttpServletRequest req)参数: req - HTTP请求 返回: 返回nc值。若未取到,返回0。 对于这个nc值,服务器端根据自己的策略可以选择不作限制,也可限定一个最大值。如果发现摘要正确但nonce使用次数超过上限,可以给客户端返回一个“过期”质询响应,其WWW-Authorize消息头中包含一个新的nonce值,并设置stale字段为true,以此要求客户端使用新的nonce值重新计算摘要。此时客户端不会重新弹出对话框让用户输入密码,而是用原来的密码和新的nonce值重新计算摘要,然后重新发出请求。对客户端用户来说,这一过程是透明的。HttpDigestAuth提供一种参数形式的setUnauth方法,用以给客户端返回“过期”质询。 setUnauth 功能: 设置 401 Unauthorized 状态码,并添加WWW-Authenticate消息头。原型: public void setUnauth(HttpServletRequest req, HttpServletResponse rsp, String realm, boolean stale)参数: req - HTTP请求 rsp - HTTP响应 realm - 指定realm字段的值,若为null则采用默认值servername:port stale - 指定stale字段的值,true表示客户端摘要正确,只是nonce值过期导致鉴权失败;false表示并非因为nonce值过期才鉴权失败。 返回: 无 调用此方法,置参数stale为true,即向客户端发挥“过期”质询。HttpDigestAuth中还有其他几种形式的setUnau方法,凡是未指定stale的,均默认为false。 无论哪种参数形式的setUnauth方法,都必须每次生成一个新的nonce值。生成nonce的算法RFC2617并没有做规定,HttpDigestAuth类在generateNonce方法中生成nonce,算法为 NOnce = BCD( MD5( : ) ) 即:取得客户端IP地址、当前时间(毫秒数),以及一个私有的key,将他们用冒号连接起来,取其MD5摘要,然后将所得的字节数组转换为十六进制字符串(即BCD码)。五、应用举例 这里通过一个例子来说明如何使用Web平台提供的API实现HTTP认证。 新建一个JSP文件AuthTest.jsp,源代码如下(读者可以将表格的右边一列拷贝到一个文本文件中,另存为AuthTest.jsp即可)。将此文件部署到一个应用服务器中(如Tomcat等),启动服务器后,用IE请求这个JSP,即可看到浏览器弹出对话框提示输入用户名和密码。 验证时,可以在IE中尝试输入正确或错误的用户名、密码,并可在对话框中选择“取消”,看看效果如何。注意如果输入了正确的用户名和密

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论