论坛首页 Java企业应用论坛

关于WSSE验证-- 一种验证用户的方法

浏览 4887 次
精华帖 (1) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2009-07-28   最后修改:2009-07-29
大家通常验证用户做法:
1. BASIC验证模式: 把用户名和密码采用Base64编码之后,放在HTTP HEADER里,发到服务器的。
2. FORM验证模式: 就什么都不处理,直接发到服务器。
3. 还有其他证书验证,摘要验证等,这些不在这篇文章讨论范围。

由于是明文传输,密码很容易被截获,从而造成密码的丢失。今天和老大讨论RESTful的模式时,想到了认证的问题,因为REST提倡无状态,我们老大提到了WSSE的问题,于是我就搜索一下。

密码传输的问题通常是用HTTPS来解决,当然这个很完美,但有些限制。有些情况下不能用HTTPS来解决,例如多个应用使用一个单独IP地址来访问时,由于服务器证书里的信息和域名是必须匹配的,所以一个应用使用了HTTPS, 而另一个就不能用了。还有一个办法就是用摘要验证,当然也可以解决这个问题,但是需要在服务器上配置相应的功能模块。如果服务器不可控(例如临时借用别人的服务器)也没有办法做到。

而WSSE的验证模式可以解决以上问题。不需在服务器做额外配置。具体过程如下:
1. 开始于两个信息: 用户名和密码。
2. 创建一个随机的nonce(不知道应该译成什么,反正就是随机的一个只能用一次的字符串),这个产生算法要够强健,不能让人猜出下一个产生的是什么。
3.创建一个"产生时间戳", 并转换成W3DTF格式
4.创建一个密码摘要:
PasswordDigest = Base64 \ (SHA1 (Nonce + CreationTimestamp + Password))

举例说明:
1.用户发一个请求:
POST /atom.cgi HTTP/1.1
Host: bob.example.com
Content-Type: application/atom+xml

<?xml version="1.0" encoding="utf-8"?>
<entry xmlns="http://purl.org/atom/ns#">
  <title>My Entry Title</title> 
  <created>2003-12-15T14:43:07Z</created> 
  <content type="application/xhtml+xml" xml:lang="en"> 
    <div xmlns="http://www.w3.org/1999/xhtml">
      <p>Hello, <em>weblog</em> world!</p>
      <p>This is my third post <strong>ever</strong>!</p>
    </div>
  </content>  
</entry>

2. 由于没有验证信息,服务器以401来响应:
HTTP/1.1 401 Unauthorized
WWW-Authenticate: WSSE realm="foo", profile="UsernameToken"


注:还有的文章讲这里服务器生成一个nonce, 然后在下一步附加到Request里,一块参与摘要生成。这个server nonce本身好像没有什么用途,但由于客户端nonce没有生成规则和长度限制(甚至如果服务器不保存以前使用过的,都无法判断是不是每次都一样的),而生成一个server nonce参与生成摘要可以保证摘要的变化性,就是每次都不一致。由于这个nonce是临时生成,一次有效,中间被人截获也无所谓。在验证时,由于是摘要验证,服务器必须保存这个nonce到验证结束,然后再及时清除。不过加了server nonce的限制,必然会使访问服务的客户端访问两次服务器才能真正访问服务,就是不能直接把身份信息附加上,直接访问服务。感觉这个就是标准的摘要验证差不多了,就变成了"请求-响应"模式了。

3. 用户输入用户名和密码,并且生成摘要,以UserToken形式发送到服务器:
POST /atom.cgi HTTP/1.1
Host: bob.example.com
Content-Type: application/atom+xml
Authorization: WSSE profile="UsernameToken"
X-WSSE: UsernameToken Username="bob", PasswordDigest="quR/EWLAV4xLf9Zqyw4pDmfV9OY=", Nonce="d36e316282959a9ed4c89851497a717f", Created="2003-12-15T14:43:07Z"

<?xml version="1.0" encoding="utf-8"?>
<entry xmlns="http://purl.org/atom/ns#">
  <title>My Entry Title</title>
  <created>2003-12-15T14:43:07Z</created>
  <content type="application/xhtml+xml" xml:lang="en">
    <div xmlns="http://www.w3.org/1999/xhtml">
      <p>Hello, <em>weblog</em> world!</p>
      <p>This is my third post <strong>ever</strong>!</p>
    </div>
  </content>
</entry>

4.服务器通过时间戳和Nonce以及服务器保存的密码进行生成摘要,如果通过验证就可以允许用户访问资源。

这样一个过程,我觉得能解决一些问题,但是还有一些疑问:
1.由于客户要生成摘要和client nonce,客户端必须具有生成它们的能力,或者浏览器支持这种协议。
现在客户端的能力都比较强大,javascript就可以实现摘要的生成。具体程序参考:http://pajhome.org.uk/crypt/md5/,目前为止好像不没有哪个浏览器支持这种协议的。

2.由于只发送摘要,并没有真正发送密码,解决中间攻击的担忧。
这个不错,就要的这种效果。

3.由于nonce是只用一次,下次就随机产生另一个,由于这个是在客户端产生的,如果产生暴力猜测密码的情况怎么办?
这里的nonce只用一次就失效,可以防止黑客的replay攻击。但这过程中没有防止暴力攻击,不过有一个时间戳应该可以利用,如在服务器判断3或者1,2秒之内不能重试登录, 这个虽然不能完全避免,但至少可以减少一些攻击次数。其实最好的解决办法就是强口令,一个强口令就把这个问题解决的比较彻底了。如果不能强制用户使用强口令的话,我们可以加入通常采用的验证码的机制。还有就是上面提到的server nonce应该也可以直到一些作用。

4.如果服务器不保存真正的密码,而是只保存摘要的话,那用这种方法岂不是不能验证用户的合法性了?
如果服务器不保存真正的密码,而是摘要。如LDAP里一般就不保存明文密码,一般数据库里也不会保存真正明文密码,这个问题我还真想不到什么办法。如果服务器的摘要算法和客户端完全一致的话,可以用以下方法生成客户端摘要:
PasswordDigest = Base64 \ (SHA1 (Nonce + CreationTimestamp + DIGEST(Password)))
就是把Password生成摘要,然后再用组合生成新的摘要。这样在服务器端也能顺利的验证用户的合法性。

我觉得这个方法可以和其他方法结合使用,应该效果不错。至少多了一层防护。

本文的思想主要来自:http://www.xml.com/pub/a/2003/12/17/dive.html, 也引用他的测试的HTTP数据。加上我自己的理解。

如有不妥,希望能够得到指正。最后感谢“Atom Authentication”文章作者Mark。但是这里面的Atom和WSSE有什么关系,并没有搞清楚,可能Atom只是WSSE的一种实现? 望知道的哥们姐妹给一些提示。








   发表时间:2009-07-29  
文章本来是发在博客里的,作为自己思路一种整理方式。但是后来仔细想想,感觉还有些地方需要讨论,今天就发到论坛上来了。希望大家能指出不足,同时也讲一下你们的系统是怎么验证用户的。
0 请登录后投票
   发表时间:2009-07-30  
难道大家对这个话题不感兴趣? 真诚希望与有这方面经验的高人讨论。
0 请登录后投票
   发表时间:2009-09-17  
从楼主的描述中nonce的字段为32位长,应该是MD5的加密,也就是说长度是等长的,是不是nonce有什么标准的规定?
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics