Learning Objectives
- 區分雜湊與加密,說明密碼為什麼只存雜湊值
- 比較明文、未加鹽、加鹽與慢速雜湊在資料外洩後的差異
- 說明字典攻擊與彩虹表的原理,以及加鹽與迭代次數各自的作用
- 以 werkzeug.security 修補註冊與登入程式,並確認舊的儲存方式已不再使用
密碼儲存與資料外洩
網站的資料庫可能因為注入漏洞、外流的備份或內部人員而落入他人之手。資料庫內容一旦外流,密碼欄位如何儲存,決定了後續的損害範圍。使用者常在不同網站使用相同的密碼,所以外洩的明文密碼也會影響其他網站。這正是撞庫攻擊(第 5 課)的來源。
雜湊(hash)把任意長度的輸入轉成固定長度的輸出,可以由輸入算出輸出,但無法由輸出直接還原輸入。加密則是可逆的:持有金鑰就能解回原文。兩者用途不同:
| 雜湊 | 加密 | |
|---|---|---|
| 可否還原 | 設計上不能 | 持有金鑰即可解密 |
| 是否需要金鑰 | 不需要 | 需要 |
| 用途 | 比對是否相同、驗證完整性 | 保護之後還要讀取的資料 |
驗證密碼時,網站不需要知道原文,只要比對雜湊值是否相同。如果網站事後能寄回你原本的密碼,代表它保存了明文或可還原的形式,這是不安全的設計。
雜湊無法還原,不代表密碼安全。 攻擊者可以把候選密碼逐一雜湊,再與外洩的值比對,這稱為字典攻擊。候選密碼可以來自常見密碼清單與其變化形式。對一般用途的雜湊函數而言,一台電腦每秒能算很多次,所以單純以 SHA-256 儲存密碼並不足夠。
本課的模擬環境。 比對只針對虛構的外洩資料,在你的瀏覽器內執行,不連線到任何系統。對未獲授權的真實資料進行比對可能觸犯法律(第 1 課)。
彩虹表與慢速雜湊
未加鹽時,同一個字典對所有網站都適用,攻擊者可以預先算好「雜湊值對應密碼」的大型對照表。彩虹表(rainbow table)是這類預先計算對照表的一種。加鹽讓每個帳號的雜湊輸入都不同,預先計算的表便失去作用;它也讓相同密碼的帳號不再一眼可辨。
加鹽解決了預先計算與重複的問題,但沒有讓單次計算變慢。慢速雜湊刻意提高每次計算的成本。使用者登入時多花不易察覺的時間,攻擊者要嘗試大量候選密碼時,這個成本會乘上候選密碼的數量。
下列參數取自 OWASP Password Storage Cheat Sheet,為建議的最低設定,應依伺服器能力再往上調整:
| 演算法 | 建議參數 | 說明 |
|---|---|---|
| Argon2id | 記憶體 46 MiB、t=1、p=1(另有相當的組合,例如 19 MiB、t=2) | OWASP 的首選,同時消耗記憶體與時間 |
| scrypt | N=2^17、r=8、p=1(另有相當的組合) | 無法使用 Argon2id 時的選擇,同樣消耗記憶體 |
| bcrypt | 工作因子至少 10 | 用於既有系統;多數實作的輸入上限為 72 位元組,應限制密碼長度 |
| PBKDF2 | HMAC-SHA256 迭代 600,000 次 | 需要符合 FIPS-140 時使用;不具記憶體成本 |
消耗記憶體的演算法,能提高以專用硬體平行運算的成本。胡椒(pepper)是全站共用、與資料庫分開保存的祕密值,屬於額外的防線,不能取代鹽。
密碼學函式庫通常會自動產生鹽,並將演算法、參數、鹽與結果存成一個字串,不需要手動處理。Flask 使用的 Werkzeug 預設採用 scrypt,產生的字串依序包含 scrypt:32768:8:1、鹽與雜湊值,以錢字號分隔。這組預設值 N=2^15、r=8、p=1 低於 OWASP 列出的組合(N=2^15 時 OWASP 列的是 p=3),正式環境可以自行指定參數,例如 method='scrypt:131072:8:1'。
密碼規則的建議
網站對使用者設定密碼的要求,也會影響字典攻擊的成效。NIST SP 800-63B-4(2025 年定稿)對驗證者的要求包括:
| 項目 | NIST SP 800-63B-4 |
|---|---|
| 最小長度 | 單獨作為一個因素時至少 15 個字元;只用於多因素驗證時至少 8 個字元 |
| 最大長度 | 應至少允許 64 個字元 |
| 組成規則 | 不得要求混合大小寫、數字、符號之類的組成規則 |
| 定期更換 | 不得要求定期更換;有證據顯示外洩時必須強制更換 |
| 封鎖清單 | 必須比對常見、預期或已外洩的密碼清單,並向使用者說明拒絕的原因 |
| 密碼管理工具 | 必須允許密碼管理工具與自動填入,應允許貼上 |
這些建議的方向是鼓勵較長且不常見的密碼,同時減少促使使用者選擇簡單密碼的規定。下方練習將所學應用到程式上。
重點整理
- 雜湊不是加密:雜湊設計上無法還原,加密持有金鑰就能解密。密碼不需要還原,只需要比對
- 雜湊無法還原,不代表密碼安全;攻擊者可以將候選密碼逐一雜湊比對
- 每個帳號都要有自己的鹽。鹽不需要保密,它使預先計算失效,並讓相同密碼的雜湊值不同
- 慢速雜湊(Argon2id、scrypt、bcrypt、PBKDF2)提高每次嘗試的成本,參數依 OWASP 建議並隨硬體調整
- 這些防護提高的是攻擊成本,弱密碼依然可能被猜中;NIST 建議以長度與封鎖清單取代組成規則與定期更換
- 實作時使用經過檢驗的函式庫,不要自行組合雜湊函數與鹽
下一課討論加密:如何保護之後還需要讀取的資料,以及雙方如何取得同一把金鑰。
小測驗
網站提供「寄回原本的密碼」功能。由此可以推斷什麼?
資料庫外洩後,攻擊者發現其中兩個帳號的未加鹽 SHA-256 值相同。這代表什麼?
為什麼 OWASP 不建議以「加鹽的 SHA-256」儲存密碼?
下列關於鹽的敘述,何者正確?
依 NIST SP 800-63B-4,下列哪一項是對驗證者的要求?