1. 程式人生 > >關於WSSE驗證-- 一種驗證使用者的方法

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

轉自: 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. <?xml version="1.0" encoding="utf-8"?>  
  5. <entry xmlns="http://purl.org/atom/ns#">  
  6.   <title>My Entry Title</title>   
  7.   <created>2003-12-15T14:43:07Z</created>   
  8.   <content type="application/xhtml+xml" xml:lang="en"
    >   
  9.     <div xmlns="http://www.w3.org/1999/xhtml">  
  10.       <p>Hello, <em>weblog</em> world!</p>  
  11.       <p>This is my third post <strong>ever</strong>!</p>  
  12.     </div>  
  13.   </content>    
  14. </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. <?xml version="1.0" encoding="utf-8"?>  
  7. <entry xmlns="http://purl.org/atom/ns#">  
  8.   <title>My Entry Title</title>  
  9.   <created>2003-12-15T14:43:07Z</created>  
  10.   <content type="application/xhtml+xml" xml:lang="en">  
  11.     <div xmlns="http://www.w3.org/1999/xhtml">  
  12.       <p>Hello, <em>weblog</em> world!</p>  
  13.       <p>This is my third post <strong>ever</strong>!</p>  
  14.     </div>  
  15.   </content>  
  16. </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的一種實現? 望知道的哥們姐妹給一些提示。