nonce和timestamp在Http安全協議中的作用


前段時間給客戶網站做新浪微博賬號登錄功能,對OAuth協議以及相關的一些安全協議做了一些研究,順便就記錄一下學習心得吧。在這里就不打算具體講OAuth的協議流程了,而是針對OAuth請求頭里的nonce(隨機數)、timestamp(時間戳)、signatrue(簽名)這些參數的作用做一下總結。

 

首先看一下HTTP規范里定義的Basic認證。

Basic認證及其安全問題

Basic認證是一個流程比較簡單的協議,整個過程可以分為以下三個步驟:

a) 客戶端使用GET方法向服務器請求資源。

b) 服務器返回401響應碼和WWW-Authentication:Basic realm=”Family”響應頭要求客戶端進行身份驗證。其中realm聲明了資源所在的域。

c) 瀏覽器接收到以上HTTP響應頭后,彈出登錄框要求用戶輸入用戶名和密碼;用戶提交的用戶名和密碼通過冒號串聯起來並對其進行BASE64編碼后再提交到服務器;服務器對提交上來的BASE64字符串進行驗證,如果驗證通過則返回200響應碼。

 

 

 

 

Basic認證雖然簡單、方便,但它只能作為對非敏感資源的訪問認證,因為它並不安全,主要表現在以下幾個方面:

1、 客戶端提交的用戶名和密碼只經過簡單的編碼,攻擊者只要竊聽到該數據包,便可很容易的將其反編碼為原始用戶名和密碼。

2、 即使客戶端使用了一種比BASE64更復雜的編碼方式使得攻擊者無法對其反編碼,攻擊者也可以使用fiddler等工具將攔截到的HTTP報文重新提交給服務器,服務器只對編碼的字符串進行驗證,所以驗證同樣能通過。這種攻擊方法稱之為重放攻擊(Replay-Attack)。

以上兩個問題也是各種身份認證協議需要考慮到的安全問題,包括OAuth、Digest認證、NTLM認證等等認證機制都使用了nonce和timestamp來解決這些問題。

Nonce、Timestamp——解決Replay-Attack問題

Nonce是由服務器生成的一個隨機數,在客戶端第一次請求頁面時將其發回客戶端;客戶端拿到這個Nonce,將其與用戶密碼串聯在一起並進行非可逆加密(MD5、SHA1等等),然后將這個加密后的字符串和用戶名、Nonce、加密算法名稱一起發回服務器;服務器使用接收到的用戶名到數據庫搜索密碼,然后跟客戶端使用同樣的算法對其進行加密,接着將其與客戶端提交上來的加密字符串進行比較,如果兩個字符串一致就表示用戶身份有效。這樣就解決了用戶密碼明文被竊取的問題,攻擊者就算知道了算法名和nonce也無法解密出密碼。

 

每個nonce只能供一個用戶使用一次,這樣就可以防止攻擊者使用重放攻擊,因為該Http報文已經無效。可選的實現方式是把每一次請求的Nonce保存到數據庫,客戶端再一次提交請求時將請求頭中得Nonce與數據庫中得數據作比較,如果已存在該Nonce,則證明該請求有可能是惡意的。然而這種解決方案也有個問題,很有可能在兩次正常的資源請求中,產生的隨機數是一樣的,這樣就造成正常的請求也被當成了攻擊,隨着數據庫中保存的隨機數不斷增多,這個問題就會變得很明顯。所以,還需要加上另外一個參數Timestamp(時間戳)。

 

Timestamp是根據服務器當前時間生成的一個字符串,與nonce放在一起,可以表示服務器在某個時間點生成的隨機數。這樣就算生成的隨機數相同,但因為它們生成的時間點不一樣,所以也算有效的隨機數。

 

問題又來了,隨着用戶訪問的增加,數據庫中保存的nonce/timestamp/username數據量會變得非常大。對於這個問題,可選的解決方案是對數據設定一個“過期時間”,比如說在數據庫中保存超過一天的數據將會被清除。如果是這樣的,攻擊者可以等待一天后,再將攔截到的HTTP報文提交到服務器,這時候因為nonce/timestamp/username數據已被服務器清除,請求將會被認為是有效的。要解決這個問題,就需要給時間戳設置一個超時時間,比如說將時間戳與服務器當前時間比較,如果相差一天則認為該時間戳是無效的。

HTTP消息體的加密

         很不幸的是,經過上面這些復雜的處理后,我們的數據傳輸仍然是不安全的。我們都知道,http報文是以明文的方式在網絡中傳輸的,包括Basic認證、Digest認證、OAuth、NTLM等等驗證這一些認證機制都只是對HTTP頭的信息作保護,而對於Http消息體的數據卻沒有作加密。以新浪首頁的登錄為例,它的賬號就是以明文的方式傳送的,如下圖所示:

 

 

 

這樣的方式是很不安全的,用戶名和密碼完全以明文的方式提交了。同樣是新浪的網站——新浪微博就在登錄前作了加密過的,如下圖所示:

 

 

 

 

 

加密的方法可以參考前面講到的nonce+timestamp的方案。不過這只解決了登錄的問題,在注冊時就不能提交使用nonce和timestamp非可逆加密了,這個時候要使用非對稱加密。在用戶打開注冊頁時,服務器生成一個公鑰/私鑰對並將公鑰返回給客戶端,客戶端使用該公鑰將密碼加密后提交到服務器,服務器使用私鑰解密后再保存到數據庫。非對稱加密算法的特點是每一個公鑰和私鑰都是一一對應的,使用公鑰加密后只有擁有私鑰的人才能進行解密,所以攻擊者截取到http報文也毫無用處。

         當然,在條件允許的情況下,可以使用SSL來實現HTTP報文的加密,這種方案是在應用層和傳輸層中間添加一個SSL層,該層使用對稱加密的方法將HTTP報文加密后再傳遞到傳輸層,如下圖所示:

 

 

 

在這之前,客戶端與服務器需要使用非對稱加密的方法來協商用於對稱加密的公鑰,對稱加密要求加密者和解密者擁有同一個密鑰(即公鑰)。當客戶端首次訪問頁面時,需要生成一個公鑰給服務器,而這個公鑰不是不可以給第三方知道的(知道了這個公鑰就可對數據進行解密了),所以需要服務器首先生成一個公鑰/密鑰對,並使用生成的公鑰加密客戶端生成的公鑰(非對稱加密),這一個過程與前面講到的注冊密碼加密的方式類似。

正因為在正式數據傳輸之前需要在服務器跟客戶端之間進行幾輪的協商,所以HTTPS相比HTTP來說安全性會高些、而性能會差些。

轉自:http://www.cnblogs.com/bestzrz/archive/2011/09/03/2164620.html


免責聲明!

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



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