WEB應用的安全的登入認證

科技小先鋒發表於2017-11-24

前些日子看到一個關於安全登入認證的博文,不過該文提到的登入認證演算法有點複雜,而且仍然存在一些安全缺陷。想到之前瞭解過的HMAC演算法,我覺得完全可以使用基於HMAC演算法來進行WEB應用的安全的登入認證。

所謂安全,其實主要是解決一個問題:在基於明文傳輸的HTTP協議下隱藏使用者輸入的密碼。當然,同時還需要考慮到使用者密碼在伺服器端同樣不能以明文儲存。

也許有人會想到一個最簡單的想法:在伺服器端把密碼用HASH演算法(比如MD5、SHA1、SHA256等)加密之後儲存,在客戶端同樣對使用者密碼進行HASH之後再傳到伺服器進行驗證……想法很好,不過仔細想想,這其實和明文密碼沒有區別,兩端的HASH計算只不過是把使用者密碼變了個樣子而已,就好像——使用者輸入的是HASH過後的密碼,然後明文傳輸進行登入一樣。

言歸正傳,考慮到伺服器端需要較為安全的儲存密碼,可以將使用者密碼進行HASH,並在HASH的時候引入SALT(鹽)。SALT在儲存密碼的時候隨機生成,並隨HASH的結果一起儲存在伺服器的資料庫內。比如我們可以建這樣一張使用者表:

欄位名 說明
username 使用者名稱,一般不區分大小寫    
salt 鹽,文字,隨機生成
hashpass 加密後的使用者密碼,通過演算法HASH(salt, password)生成

需要注意的是,這裡在計算hashpass的時候也可以將使用者名稱計算在內,但要考慮使用者名稱不分割槽大小寫時的情況,所以可以是:HASH(L_CASE(username), salt, password)

現在不考慮安全傳輸的情況下,使用者登入驗證過程可能是這樣:

  1. 1. 使用者輸入使用者名稱U和密碼P,提交到服務端
  2. 2. 服務端通過U找到資料庫中的相應的salt和hashpass
  3. 3. 使用salt計算出使用者輸入密碼的hash值,H = HASH(salt, P)

    或者是HMAC(L_CASE(U), salt, P)
  4. 4. 對比計算結果H和資料庫中取出來的hashpass,如果一致,則驗證成功

這裡從客戶端傳到伺服器的P是一個明文。接下來要考慮的就是把這個明文變成不可識別也不可破解的密文,當然首選HASH演算法。

為什麼不選DES/AES之類的對稱加密演算法呢——很顯然的一個道理,客戶端是通過JS來計算加密的,如果選用DES加密演算法,使用者密碼在這裡可能充當兩種角色,一種是Key,這種情況下,要求服務端用同樣的Key來解密,那麼Key就需要以明文方式儲存,破壞了儲存密碼的安全性;另外一種角色是被加密的資料,但這樣一來,Key就成了能被擷取的明文(由伺服器明文傳輸過來,或直接寫在JS原始檔裡),在有Key的情況下,DES可以直接解密,使用者密碼就暴露了。再深入一點思考,如果把使用者密碼先按伺服器端的演算法計算HASH,再通過DES加密輸入到伺服器呢?——其實HASH過程已經就把使用者密碼進行了不可逆的加密,再進行一次DES有何意義呢? 

那麼,相對安全的,按HMAC演算法設計出來的登入驗證過程應該是這樣:

  1. 1. 客戶端發訊息給伺服器請求登入,該訊息包含使用者名稱U
  2. 2. 伺服器取得U,從資料庫中檢索出salt,同時產生一個隨機數R,一起返回給客戶端
  3. 3. 客戶端進行第一次HASH演算法,得到需要在伺服器端驗證的密碼:H1 = HMAC(salt, P)
    或HMAC(L_CASE(U), salt, P)
  4. 4. 客戶端進行第二次HASH演算法,得到需要傳送回伺服器的HASH值:H2 = HMAC(HASH(r), H1)
  5. 5. 客戶端將H2傳送到伺服器
  6. 6. 伺服器根據U檢索到資料庫中的hashpass,用同樣的HASH演算法計算HS = HMAC(HASH(R), hashpass)
  7. 7. 如果hashpass和客戶端計算的中間資料H1一致,則HS與客戶端傳入的H2一致,驗證成功
  8. 8. 不管驗證成功與否,R被拋棄。下次登入過程由伺服器重新產生新的隨機數R1參與計算。

這裡的安全保證在於:

  1. 1. 可以被擷取或計算出來的,只有U, salt,R和H2,甚至就算資料庫的hashpass被洩漏,仍然不可能計算出使用者密碼P。
  2. 2. 用於驗證的H2不能重複使用。R作為一個臨時隨機數,僅在當前登入過程有效,所以R參與了計算的結果H2不能用於下一次登入。

 

本文轉自邊城__ 51CTO部落格,原文連結:http://blog.51cto.com/jamesfancy/1161210,如需轉載請自行聯絡原作者


相關文章