翻譯自
https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Password_Storage_Cheat_Sheet.md
密碼存儲小抄
簡介
這份小抄為您提供了有關身份驗證密碼存儲的正確方法建議。當密碼被存儲時,必須保護它們免受攻擊者的侵害,即使應用程序或數據庫被入侵。幸運的是,大多數現代語言和框架提供了內置功能,以幫助安全地存儲密碼。
然而,一旦攻擊者獲得存儲的密碼雜湊,他們總是能夠離線暴力破解雜湊。防禦者可以通過選擇盡可能資源密集的雜湊算法來減緩離線攻擊速度。
總結我們的建議:
- 使用Argon2id,最小配置為19 MiB的內存,迭代次數為2,並且並行度為1。
- 如果Argon2id不可用,則使用scrypt,最小CPU/內存成本參數為(2^17),最小塊大小為8(1024字節),並且並行化參數為1。
- 對於使用bcrypt的舊系統,使用10或更多的工作因數,並且密碼限制為72字節。
- 如果需要符合FIPS-140,則使用PBKDF2,工作因數為600,000或更多,並設置內部雜湊函數為HMAC-SHA-256。
- 考慮使用pepper以提供額外的深度防禦(儘管單獨使用時,它不提供額外的安全特性)。
背景
雜湊 vs 加密
雜湊和加密可以保護敏感數據安全,但在幾乎所有情況下,密碼應該被雜湊,而不是加密。
因為雜湊是單向函數(即不可能“解密”雜湊並獲取原始明文值),這是密碼驗證的最合適方法。即使攻擊者獲得了雜湊密碼,他們也無法使用它來登錄受害者。
由於加密是雙向函數,攻擊者可以從加密數據中檢索原始明文。它可以用於存儲用戶地址等數據,因為這些數據在用戶檔案中以明文顯示。對其地址進行雜湊將導致一團亂。
唯一應該在密碼中使用加密的情況是在必須獲取原始明文密碼的邊緣情況下。如果應用程式需要使用密碼與不支援現代方式以程式設計方式授予訪問權限的其他系統進行身份驗證,例如 OpenID Connect (OIDC),則可能需要這樣做。在可能的情況下,應使用替代架構以避免以加密形式存儲密碼的需求。
有關加密的進一步指導,請參閱加密存儲秘訣表。
當密碼雜湊可以被破解時
使用現代雜湊算法存儲的強密碼,並遵循最佳的雜湊實踐,對於攻擊者來說應該是幾乎不可能破解的。 作為應用程式擁有者,選擇一種現代的雜湊算法是您的責任。
然而,在某些情況下,攻擊者可以在某些情況下“破解”雜湊,方法如下:
- 選擇您認為受害者已選擇的密碼(例如
password1!
) - 計算雜湊
- 將您計算的雜湊與受害者的雜湊進行比較。如果它們匹配,則您已正確“破解”雜湊,現在知道他們密碼的明文值。
通常,攻擊者將使用大量潛在候選密碼列表重複此過程,例如:
- 從其他受侵擾網站獲取的密碼列表
- 暴力破解(嘗試每個可能的候選)
- 常見密碼的字典或單詞列表
儘管排列組合的數量可能是巨大的,但使用高速硬件(例如 GPU)和許多租用伺服器的雲服務,對於攻擊者來說,成功進行密碼破解的成本相對較小,特別是當未遵循雜湊的最佳實踐時。
增強密碼存儲的方法
加鹽
鹽是一個唯一的、隨機生成的字符串,它作為雜湊過程的一部分添加到每個密碼中。由於鹽對每個用戶都是唯一的,攻擊者必須使用相應的鹽一次破解一個雜湊,而不是計算一次雜湊並將其與每個存儲的雜湊進行比較。這使得破解大量雜湊變得顯著困難,因為所需的時間與雜湊數量成正比增長。
鹽也可以防止攻擊者使用彩虹表或基於數據庫的查找預先計算哈希。最後,鹽化意味著無法確定兩個使用者是否有相同的密碼,除非破解哈希,因為不同的鹽將導致不同的哈希,即使密碼相同。
現代哈希算法 如Argon2id、bcrypt和PBKDF2會自動對密碼進行鹽化,因此在使用它們時不需要進行額外步驟。
加胡椒
胡椒 可以用來提供額外的保護層,除了鹽化。它可以防止攻擊者在只能訪問數據庫時破解任何哈希,例如,如果他們利用了SQL注入漏洞或獲取了數據庫的備份。胡椒策略不會以任何方式影響密碼哈希函數。
例如,一種胡椒策略是像往常一樣對密碼進行哈希(使用密碼哈希算法),然後在將密碼哈希存儲到數據庫之前對原始密碼哈希使用HMAC(例如,HMAC-SHA256、HMAC-SHA512,取決於所需的輸出長度),其中胡椒充當HMAC金鑰。
- 胡椒是存儲密碼之間共享的,而不像鹽一樣是唯一的。
- 與密碼鹽不同,胡椒不應存儲在數據庫中。
- 胡椒是秘密,應存儲在”秘密保險庫”或HSM(硬體安全模塊)中。有關安全存儲秘密的更多信息,請參見秘密管理速查表。
- 與任何其他加密金鑰一樣,應考慮胡椒輪換策略。
使用工作因子
工作因子是對每個密碼執行的哈希算法迭代次數(通常實際上是2^work
次迭代)。工作因子通常存儲在哈希輸出中。它使計算哈希變得更加耗費計算資源,進而降低了攻擊者嘗試破解密碼哈希的速度和/或增加成本。
當您選擇工作因子時,應在安全性和效能之間取得平衡。雖然較高的工作因子使雜湊更難以被攻擊者破解,但會減慢驗證登入嘗試的過程。如果工作因子設定過高,應用程式的效能可能會下降,這可能被攻擊者利用,通過大量的登入嘗試使伺服器的 CPU 耗盡,從而發動拒絕服務攻擊。
沒有理想的工作因子的黃金法則 - 這將取決於伺服器的效能和應用程式上的使用者數量。確定最佳的工作因子將需要對應用程式使用的特定伺服器進行實驗。一般來說,計算一個雜湊值應該需要少於一秒的時間。
升級工作因子
擁有工作因子的一個關鍵優勢是隨著硬體變得更強大和更便宜,可以逐步增加工作因子。
升級工作因子的最常見方法是等待使用者下次進行身份驗證,然後使用新的工作因子重新對其密碼進行雜湊。不同的雜湊值將具有不同的工作因子,如果使用者不再登入應用程式,則可能永遠不會升級雜湊值。根據應用程式的情況,可能適合刪除舊的密碼雜湊值,並要求使用者在下次需要登入時重設其密碼,以避免存儲舊的且不太安全的雜湊值。
密碼雜湊演算法
一些現代的雜湊演算法是專門設計用於安全地存儲密碼。這意味著它們應該是慢的(不像 MD5 和 SHA-1 等旨在快速的演算法),您可以通過改變工作因子來改變它們的運行速度。
您不需要隱藏應用程式使用的密碼雜湊演算法。如果您使用了一個現代的密碼雜湊演算法並配置了正確的參數,可以公開聲明應用程式使用哪些密碼雜湊演算法,並在這裡列出。
三種應該考慮的雜湊演算法:
Argon2id
Argon2 是 2015 年 密碼雜湊競賽 的冠軍。在三個 Argon2 版本中,使用 Argon2id 變體,因為它提供了一種平衡的方法來抵抗側信道和基於 GPU 的攻擊。
與其他演算法不同,Argon2id 不是一個簡單的工作因子,而是有三個可以配置的不同參數:最小記憶體大小的基本最小值 (m)、迭代的最小次數 (t) 和平行度 (p)。我們建議以下配置設定:
- m=47104 (46 MiB), t=1, p=1 (不要與 Argon2i 一起使用)
- m=19456 (19 MiB), t=2, p=1 (不要與 Argon2i 一起使用)
- m=12288 (12 MiB), t=3, p=1
- m=9216 (9 MiB), t=4, p=1
- m=7168 (7 MiB), t=5, p=1
這些配置設定提供了相同水準的防禦,唯一的區別在於 CPU 和 RAM 使用之間的權衡。
scrypt
scrypt 是由 Colin Percival 創建的基於密碼的金鑰導出函數。雖然 Argon2id 應該是密碼雜湊的最佳選擇,但在前者不可用時,應該使用 scrypt。
像 Argon2id 一樣,scrypt 有三個可以配置的不同參數:最小 CPU/記憶體成本參數 (N)、區塊大小 (r) 和平行度 (p)。使用以下其中一個設定:
- N=2^17 (128 MiB), r=8 (1024 bytes), p=1
- N=2^16 (64 MiB), r=8 (1024 bytes), p=2
- N=2^15 (32 MiB), r=8 (1024 bytes), p=3
- N=2^14 (16 MiB), r=8 (1024 bytes), p=5
- N=2^13 (8 MiB), r=8 (1024 bytes), p=10
這些配置設定提供了相同水準的防禦。唯一的區別在於 CPU 和 RAM 使用之間的權衡。
bcrypt
bcrypt 密碼雜湊函數應該是在傳統系統中進行密碼存儲的最佳選擇,或者如果需要 PBKDF2 以達到 FIPS-140 合規性。
工作因子應盡可能大,以符合驗證伺服器的效能,最低為 10。
bcrypt 的輸入限制
bcrypt 在大多數實作中有最大長度限制為 72 個位元組,因此您應強制執行最大密碼長度為 72 個位元組(如果使用的 bcrypt 實作有較小的限制,則應該是 72 個位元組或更少)。
使用 bcrypt 對密碼進行預先雜湊
另一種方法是使用快速演算法(例如 SHA-256)對用戶提供的密碼進行預先雜湊,然後使用 bcrypt 對生成的雜湊進行雜湊(即 bcrypt(base64(hmac-sha256(data:$password, key:$pepper)), $salt, $cost)
)。這是一種危險(但常見)的做法,應該避免,因為在將 bcrypt 與其他雜湊函數結合使用時可能會出現密碼剝離和其他問題。
PBKDF2
由於NIST推薦使用PBKDF2,並且具有 FIPS-140 驗證的實作,因此在需要時應該優先選擇該演算法。
PBKDF2 演算法要求您選擇內部雜湊演算法,例如 HMAC 或各種其他雜湊演算法。HMAC-SHA-256 得到廣泛支持,並且被 NIST 推薦。
PBKDF2 的工作因子是通過迭代次數實現的,應根據所使用的內部雜湊演算法設置不同。
- PBKDF2-HMAC-SHA1:1,300,000 次迭代
- PBKDF2-HMAC-SHA256:600,000 次迭代
- PBKDF2-HMAC-SHA512:210,000 次迭代
平行 PBKDF2
- PPBKDF2-SHA512:成本 2
- PPBKDF2-SHA256:成本 5
- PPBKDF2-SHA1:成本 10
這些配置設置在提供的防禦方面是等效的。(根據 RTX 4000 GPU 測試,截至 2022 年 12 月的數字)
PBKDF2 預先雜湊
當 PBKDF2 與 HMAC 一起使用,且密碼長度超過雜湊函數的區塊大小(SHA-256 的區塊大小為 64 個位元組)時,密碼將自動進行預先雜湊。例如,密碼 “This is a password longer than 512 bits which is the block size of SHA-256” 將轉換為雜湊值(十六進位):fa91498c139805af73f7ba275cca071e78d78675027000c99a9925e2ec92eedd
。
良好的PBKDF2實作在昂貴的迭代雜湊階段之前執行預先雜湊。然而,一些實作在每次迭代中執行轉換,這可能使對長密碼進行雜湊比對短密碼更加昂貴。當用戶提供非常長的密碼時,可能會出現潛在的拒絕服務漏洞,例如2013年Django中發表的漏洞。手動預先雜湊可以降低這種風險,但需要在預先雜湊步驟中添加鹽。
升級舊雜湊
使用較不安全的雜湊算法(例如MD5或SHA-1)的舊應用程式可以按照上述描述升級為現代密碼雜湊算法。當用戶輸入他們的密碼(通常是通過應用程式進行身份驗證)時,該輸入應使用新算法重新進行雜湊。防禦者應該使用者的當前密碼過期並要求他們輸入新密碼,以使他們的舊(較不安全)密碼雜湊對攻擊者不再有用。
然而,這意味著舊(較不安全)密碼雜湊將存儲在數據庫中,直到用戶登錄。您可以採取以下兩種方法之一來避免這種困境。
升級方法一:使長時間不活動的用戶的密碼雜湊過期並刪除,並要求他們重設密碼以再次登錄。儘管安全,但這種方法並不特別用戶友好。使許多用戶的密碼過期可能會對支援人員造成問題,或者被用戶解讀為遭受入侵的跡象。
升級方法二:將現有的密碼雜湊用作更安全算法的輸入。例如,如果應用程式最初將密碼存儲為md5($password)
,則可以輕鬆升級為bcrypt(md5($password))
。分層雜湊避免了需要知道原始密碼的需求;然而,這可能使雜湊更容易破解。下次用戶登錄時,這些雜湊應該被用戶的密碼的直接雜湊所取代。
請記住,一旦選擇了密碼雜湊方法,將來必須升級,因此請確保升級您的雜湊演算法盡可能簡單。在過渡期間,應允許使用舊版和新版雜湊演算法的混合。如果密碼雜湊演算法和加密係數以標準格式與密碼一起存儲,例如模組化PHC字串格式,則使用混合雜湊演算法將更容易。
國際字符
您的雜湊函式庫必須能夠接受各種字符,並且應與所有Unicode碼點兼容,以便用戶可以在現代設備上使用所有可用字符範圍,尤其是移動鍵盤。他們應該能夠從各種語言中選擇密碼,並包括象形文字。在對用戶輸入進行雜湊之前,不應減少其熵,並且密碼雜湊函式庫需要能夠使用可能包含NULL字節的輸入。