2013-01-18 24 views
12

我正在將網站切換到導軌。這是一個擁有5萬用戶的大型網站。問題是,現有的密碼哈希方法是極其弱。我有兩個選擇:將舊密碼移動到新的哈希算法?

1)切換到一個新的算法,生成每個人的隨機密碼,然後通過電子郵件發送的密碼,並要求變更後立即

2)實施新的算法,但在此之前使用的舊然後散列結果。例如:

密碼:ABCDEF =算法1 => xj31ndn =算法2 => $ 21aafadsada214

任何新的密碼,將需要經過原始算法(MD5),然後有一個散列如果結果這有什麼意義?這是否有缺點?

回答

2

您可以創建新密碼字段已經更新了他們使用新密碼方法密碼所有用戶,只需用你的選項2.

與強制更新密碼在登錄與所有用戶結合這個大家更新舊密碼方法會自動將所有活動用戶移至新密碼方法。

1

另一種可能是保留兩個哈希值可用於在數據庫中單獨列遷移階段:

  • 如果新的哈希值不登錄時存在的,與舊的哈希檢查,並保存新的散列並刪除舊的散列。
  • 如果新的散列存在,只用這個來驗證。

因此,一段時間後,您將只剩下新的哈希 - 至少對於至少登錄一次的用戶。

20

通常不需要重置密碼,只需等待用戶下次登錄即可。

  1. 首先嚐試使用新算法驗證輸入的密碼。然後,新密碼和已經轉換的密碼不再需要更長的時間進行驗證。
  2. 如果不匹配,請將其與舊的散列算法進行比較。
  3. 如果舊的散列值匹配,那麼您可以計算並存儲新的散列值,因爲您知道密碼。

每個密碼存儲系統都必須有切換到更好散列算法的選項,您的問題不是一次性遷移問題。像BCrypt這樣的好密碼哈希算法有成本因素,有時你必須增加這個成本因素(因爲硬件更快),那麼你需要完全相同的程序來完成遷移。

如果你的第一個算法非常弱,並且你希望立即給予更多的保護,那麼對於散列舊散列的選項2是一件好事。在這種情況下,您可以計算雙重散列,並用新的雙重散列替換數據庫中的舊散列。

$newHashToStoreInTheDb = new_hash($oldHashFromDb) 

你也應該紀念這個密碼散列(see why),這樣你就可以將其識別爲雙哈希值。這可以在單獨的數據庫字段中完成,也可以包含自己的簽名。現代密碼哈希函數還包括算法的簽名,以便他們可以升級到更新的算法,並且仍然可以驗證較舊的哈希值。這個例子顯示了BCrypt哈希的簽名:

$2y$10$nOUIs5kJ7naTuTFkBy1veuK0kSxUFXfuaOKdOKf9xYT0KKIGSJwFa 
___ 
| 
signature of hash-algorithm = 2y = BCrypt 

驗證會像這樣運行:

  1. 決定是否雙哈希值。
  2. 如果它是一個新的哈希,調用新的哈希函數來驗證所輸入的密碼,就大功告成了。
  3. 如果是雙散列,使用雙散列算法new_hash(old_hash($password))進行比較。
  4. 如若雙散列值匹配,那麼你可以計算和存儲新的哈希值。
+0

在我看來,雙重哈希是一個可怕的想法。您散列密碼的原因之一是,如果您的散列被泄露,它們仍然無法作爲用戶進行身份驗證。 如果您首先執行new_hash($ raw_password),則用戶可以通過在密碼字段中輸入舊的泄漏散列來登錄。擊敗了轉向安全哈希算法的目的。 – Lemon

+0

@Lemon - 當然,數據庫中的舊密碼哈希將替換爲雙哈希,但您說得對,這不是最佳解決方案。我編輯了答案以顯示最佳實踐,但仍使用雙哈希,但標記了舊哈希。 – martinstoeckli

8

最簡單的解決方案可能是向數據庫添加「密碼哈希類型」列。最初設置爲「舊」;當用戶登錄時,使用新算法重新對散列密碼進行重新散列,並將數據庫類型設置爲「新」。

此方法的一種變體是將散列類型存儲爲部分的散列字符串。該作品一樣好,只要你能明確告訴不同的hash格式分開,並有優勢,你也可以包括在相同字符串的任何其他需要的參數(如saltkey stretching工作因素),而不必爲每個數據庫添加額外的字段。

例如,這是通常用於modern Unix crypt(3) implementations的方法(和在各種高級語言如PHP相應的功能):經典的DES爲基礎的(和可怕弱)密碼哈希看起來像abJnggxhB/yWI,而(略)更現代的哈希可能看起來像$1$z75qouSC$nNVPAk1FTd0yVd62S3sjR1,其中1指定的散列方法,z75qouSC是鹽和nNVPAk1FTd0yVd62S3sjR1實際哈希,和分隔符$選擇,因爲它不能在老式的DES哈希出現。


你建議的方法,在新的散列計算公式爲:

hash = new_hash(old_hash(password)) 

可以在某些情況下非常有用,因爲它允許所有現有的記錄進行更新,而無需等待用戶登錄。但是,如果舊的散列函數保留了密碼中足夠多的熵,則它是安全的。

例如,即使是一個相當古老而薄弱的加密散列函數,如未加註的MD5也足夠好,因爲它的輸出取決於整個輸入,並且有高達128位的熵,這比任何密碼無論如何將會有(並且綽綽有餘以承受暴力攻擊)。在另一方面,試圖使用舊的基於DES加密中應用這種結構(3)功能作爲老散列要災難性,因爲舊的crypt(3)將全部忽略,但每個密碼的前8個字符(如以及即使是那些角色的最重要的位)。

+0

只需添加存儲'舊'或'新'作爲數據值是一個可怕的想法。新的之後會發生什麼?我曾經使用過一種名爲「NewModel」的數據模型,但這只是一個例外。這是一個不斷混淆的來源。 – marcp