關於WSSE驗證-- 一種驗證用戶的方法


 

大家通常驗證用戶做法: 
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的一種實現? 望知道的哥們姐妹給一些提示。 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM