前段時間給客戶網站作新浪微博帳號登陸功能,對OAuth協議以及相關的一些安全協議作了一些研究,順便就記錄一下學習心得吧。在這裏就不打算具體講OAuth的協議流程了,而是針對OAuth請求頭裏的nonce(隨機數)、timestamp(時間戳)、signatrue(簽名)這些參數的做用作一下總結。html
首先看一下HTTP規範裏定義的Basic認證。算法
Basic認證及其安全問題數據庫
Basic認證是一個流程比較簡單的協議,整個過程能夠分爲如下三個步驟:瀏覽器
a) 客戶端使用GET方法向服務器請求資源。安全
b) 服務器返回401響應碼和WWW-Authentication:Basic realm=」Family」響應頭要求客戶端進行身份驗證。其中realm聲明瞭資源所在的域。服務器
c) 瀏覽器接收到以上HTTP響應頭後,彈出登陸框要求用戶輸入用戶名和密碼;用戶提交的用戶名和密碼經過冒號串聯起來並對其進行BASE64編碼後再提交到服務器;服務器對提交上來的BASE64字符串進行驗證,若是驗證經過則返回200響應碼。網絡
Basic認證雖然簡單、方便,但它只能做爲對非敏感資源的訪問認證,由於它並不安全,主要表如今如下幾個方面:工具
一、 客戶端提交的用戶名和密碼只通過簡單的編碼,攻擊者只要竊聽到該數據包,即可很容易的將其反編碼爲原始用戶名和密碼。性能
二、 即便客戶端使用了一種比BASE64更復雜的編碼方式使得攻擊者沒法對其反編碼,攻擊者也可使用fiddler等工具將攔截到的HTTP報文從新提交給服務器,服務器只對編碼的字符串進行驗證,因此驗證一樣能經過。這種攻擊方法稱之爲重放攻擊(Replay-Attack)。學習
以上兩個問題也是各類身份認證協議須要考慮到的安全問題,包括OAuth、Digest認證、NTLM認證等等認證機制都使用了nonce和timestamp來解決這些問題。
Nonce、Timestamp——解決Replay-Attack問題
Nonce是由服務器生成的一個隨機數,在客戶端第一次請求頁面時將其發回客戶端;客戶端拿到這個Nonce,將其與用戶密碼串聯在一塊兒並進行非可逆加密(MD五、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