用於密碼驗證的修補 SHA1 嘗試
這是一個經典場景:對於我們基於 Web 的身份驗證平台,我們有一個使用者名和一個密碼欄位。使用者輸入這些值並按下登錄。瀏覽器收集使用者數據,計算密碼摘要並將所有內容髮送到伺服器端。我們不想通過網路發送密碼,它可能不安全。
在伺服器端,我們有一個數據庫,它將密碼的雜湊值儲存在一個表中(以及其他東西)。
最初我們為此目的使用 MD5,但過了一段時間,我們放棄了這個想法,因為它是具有大型可用彩虹表的最受黑客攻擊的消息摘要,因此一旦有人擷取數據包,他們就可以輕鬆猜出密碼(如果密碼很弱的話) .
現在我們已經切換到 SHA1 來計算摘要……只有一個問題。最初的數據庫佈局是使用 32 個字元作為密碼的消息摘要(MD5 十六進製字元串的長度)……但是 SHA1 是 40 個字元長(轉換為十六進製字節時)。更大的問題是我們不想增加消息摘要表列的長度(也不想增加使用的消息摘要本身的長度),因為摘要值在一些算法的某些階段使用,它依賴於事實它有 32 個字元。
因此架構團隊的某個人提出了這個想法:讓我們在登錄過程中添加一個額外的驗證步驟,並向使用者詢問一個 4 位長的密碼。當我們有這個 PIN 時,我們只需從密碼的 SHA1 摘要中刪除兩次在給定 PIN 位置找到的字元(從開頭和結尾),這樣我們最終得到一個 32 個字元長的摘要,這無法追溯到密碼,因為它沒有獲得所有必需的資訊。
只有一件事困擾我們:在應用兩種不同的字元刪除算法(基於兩個不同的 PIN)後給出兩個不同雜湊值的兩個不同密碼給出相同結果的理論上的可能性是多少。
而且由於我們的團隊中沒有密碼分析員或密碼學家,我們必須求助於社區 :) 感謝您的幫助。
簡短的回答:不要。使用密碼散列,如 PBKDF2、scrypt 或 bcrypt。
此外,如果可能的話,請使用一個庫來為您處理像密碼數據庫這樣的低級內容。例如,如果您使用 Python,passlib 可能會起作用。如果這聽起來很生硬,我很抱歉,但事實就是這樣。
要回答您的實際問題:
只有一件事困擾我們:在應用兩種不同的字元刪除算法(基於兩個不同的 PIN)後給出兩個不同雜湊值的兩個不同密碼給出相同結果的理論上的可能性是多少。
無論 PIN 是否不同,兩個*不同密碼給出相同最終雜湊的機會都是相同的。*機會是 $ 2^{-n} $ 為 $ n $ -bit 最終雜湊。IE $ 2^{-128} $ 對於 128 位雜湊。
(要了解為什麼 PIN 無關緊要,請將輸出雜湊視為隨機數。這是您能做的最好的事情。不同的 PIN 只有在密碼雜湊相等時才有意義。)
您可以改為截斷 hash,包括要與密碼一起散列的字元串中的 PIN。此外,如果您採用這種方式,您不妨使用被認為是安全的 SHA-256,而不是 SHA-1,後者俱有截斷可能實用的理論攻擊。
同樣,您不應該只使用普通雜湊來保護密碼。此外,您在客戶端中散列密碼的想法是不安全的:
瀏覽器收集使用者數據,計算密碼摘要並將所有內容髮送到伺服器端。我們不想通過網路發送密碼,它可能不安全。
這是一個很好的直覺,但它不像你描述的那樣起作用。如果您不在伺服器端進行雜湊,任何竊取您的密碼數據庫的人都可以使用雜湊登錄。(您的網站/應用程序可能會要求輸入密碼,但攻擊者不必使用它。)
您可以在客戶端和伺服器上進行雜湊處理,儘管這只會保護明文密碼,以防加密被破壞。這對於重用密碼但不會保護他們在您系統上的帳戶而不僅僅是在伺服器上進行散列的使用者來說很好。
(除非您發送明文密碼的連接是加密的,否則竊聽者總是可以獲取密碼/雜湊並登錄!)
另一項建議:如果您在密碼數據庫中確實限制為 32 個字元,請考慮盡可能使用 base 64 編碼的雜湊值。這允許您儲存 192 位密碼雜湊。二進制會更好,允許使用 SHA-256 的 scrypt 或 PBKDF2 的全部 256 位。