2012-10-17 176 views
1

我正在用MySQL創建一個Django網站。我已經決定使用內置的pbkdf2-sha256中的Django和隨機生成的salt hash來存儲用戶的密碼。從用戶密碼安全生成加密密鑰?

但是,該網站還需要存儲許多其他網站(不使用oauth)的第三方登錄憑證。所以我正在研究AES-256加密,當然這個問題成爲安全存儲加密密鑰的地方。

現在這裏是我的解決方案:讓每個加密密鑰=用戶實際密碼和隨機生成的鹽的哈希值(與用於存儲密碼的哈希值不同)。鹽將存儲在表中,實際的密碼和它的散列顯然不是。因此,加密密鑰將在登錄時生成並臨時存儲,但在註銷時到期。進一步說,如果不破解原始的pbkdf2-sha256哈希值,那麼會損害服務器的人無法生成加密密鑰,即使如此,它只會針對該用戶,而不是通用密鑰。

缺點是,如果他們更改/重置密碼,他們將不得不爲每個網站重新輸入憑據。但這並不是什麼大問題,似乎比在服務器或其他服務器上存儲密鑰更安全。

但是我只知道24小時前的散列是什麼,所以我知道什麼。我是否忽略了某些東西,或者這是相當安全的?或者,還有更好的方法?

+0

這就是[PBKDF](http://en.wikipedia.org/wiki/PBKDF2)*是*:基於密碼的密鑰推導函數。 –

+0

我意識到這一點。這就是爲什麼我用它來創建單向密鑰而不是用戶密碼。我建議再次使用不同的密碼來作爲不同登錄憑證的單獨加密密鑰。這樣攻擊者無法獲得加密密鑰 –

+0

您可以生成高熵鹽,並使用salt +密碼上的PBKDF來獲得密鑰+ IV來加密數據並存儲salt和加密數據,這是*長期*存儲。在需要時,您可以使用存儲的salt和密碼(從* where *?中檢索)訪問加密數據。但是你沒有密碼。您只在您的用戶信息中存儲單向散列值。登錄表單帖子已經過去了。除非你每次需要時詢問用戶pwd *,否則你需要將它存儲在某處*,這是你的真正問題,*你在哪裏存儲PWD *? –

回答

3

您提到的算法PBKDF2實際上是爲這個明確的目的而設計的。

因此,工作流程將生成一個隨機鹽。然後將其存儲在用戶的數據庫中。

使用具有較高迭代計數和salt的PBKDF2生成640位密鑰材料(80字節)。

的前128位成爲密碼

的IV下256個​​比特成爲密碼密鑰

最後256位成爲MAC密鑰(密鑰(用於AES-256的密鑰)用於驗證加密)。

key = PBKDF2-SHA256(password, salt, 50000, 80) 
iv = key[0:128] 
cipherKey = key[128:384] 
macKey = key[384:640] 

然後,使用加密這些密鑰(僞碼):

ciphertext = AES-256-CBC(data, cipherKey, iv) 
authtext = SHA256-HMAC(ciphertext, macKey) 
result = '{}{}'.format(authtext, ciphertext) 

現在,解密,剛剛散步回來反向...

key = PBKDF2-SHA256(password, salt, 50000, 80) 
iv = key[0:128] 
cipherKey = key[128:384] 
macKey = key[384:640] 

authtext = result[0:32] 
ciphertext = result[32:] 

if !timingSafeComparison(authtext, SHA256-HMAC(ciphertext, macKey)): 
    return false 

return AES-256-CBC-DECRYPT(ciphertext, cipherKey, iv) 

是,如果您的用戶忘記密碼,則所有加密的數據都將消失。但那就是你想要的,對吧?

+0

這種方法存在的問題是,當您從中拉出超過自然尺寸時,PBKDF2的成本會增加。攻擊者可能只對部分輸出感興趣,因爲這足以進行確認,從而允許他加快密碼搜索的速度,而不是合法的散列器。我更喜歡從PBKDF2輸出自然大小,然後使用HKDF生成單個的密鑰。 – CodesInChaos