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

来源:互联网 发布:ubuntu 安装类型 win7 编辑:程序博客网 时间:2024/04/28 20:03


转自: http://www.iteye.com/topic/434867


大家通常验证用户做法: 
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.用户发一个请求: 

Http代码  收藏代码
  1. POST /atom.cgi HTTP/1.1  
  2. Host: bob.example.com  
  3. Content-Type: application/atom+xml  
  4.   
  5. <?xml version="1.0" encoding="utf-8"?>  
  6. <entry xmlns="http://purl.org/atom/ns#">  
  7.   <title>My Entry Title</title>   
  8.   <created>2003-12-15T14:43:07Z</created>   
  9.   <content type="application/xhtml+xml" xml:lang="en">   
  10.     <div xmlns="http://www.w3.org/1999/xhtml">  
  11.       <p>Hello, <em>weblog</em> world!</p>  
  12.       <p>This is my third post <strong>ever</strong>!</p>  
  13.     </div>  
  14.   </content>    
  15. </entry>  

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


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

3. 用户输入用户名和密码,并且生成摘要,以UserToken形式发送到服务器: 
Http代码  收藏代码
  1. POST /atom.cgi HTTP/1.1  
  2. Host: bob.example.com  
  3. Content-Type: application/atom+xml  
  4. Authorization: WSSE profile="UsernameToken"  
  5. X-WSSE: UsernameToken Username="bob", PasswordDigest="quR/EWLAV4xLf9Zqyw4pDmfV9OY=", Nonce="d36e316282959a9ed4c89851497a717f", Created="2003-12-15T14:43:07Z"  
  6.   
  7. <?xml version="1.0" encoding="utf-8"?>  
  8. <entry xmlns="http://purl.org/atom/ns#">  
  9.   <title>My Entry Title</title>  
  10.   <created>2003-12-15T14:43:07Z</created>  
  11.   <content type="application/xhtml+xml" xml:lang="en">  
  12.     <div xmlns="http://www.w3.org/1999/xhtml">  
  13.       <p>Hello, <em>weblog</em> world!</p>  
  14.       <p>This is my third post <strong>ever</strong>!</p>  
  15.     </div>  
  16.   </content>  
  17. </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的一种实现? 望知道的哥们姐妹给一些提示。 


0 0