本地弱密碼名單能證明什麼,為什麼它不是全網撞庫

「測一下這組密碼有沒有外洩」常被講成同一件事。實際至少有三種做法:把明文交給網站、只送雜湊前綴去查 Have I Been Pwned、在目前分頁對照一份公開高頻名單。核對方法不是相信「本地」兩個字,而是看這一次請求裡走的是哪一種,以及命中、未命中各自能寫進工單的哪一句。

先記結論:本機弱密碼名單能支持的只有「這串字元像不像已被廣泛濫用的密碼」。未命中不能證明從未外洩;命中只代表太常見,應立刻更換。Have I Been Pwned 的密碼範圍查詢是另一套協定,只送 SHA-1 前五碼。把明文貼進任何「線上檢測」框之前,先確認對方走的是哪一種。

一句話先回答搜尋意圖

本機弱密碼名單能證明的,只有一件很窄的事實:你輸入的這串字元,在「已經下載到目前分頁的那份公開高頻名單」裡能不能被比對上。它證明不了「全網沒見過」,也回答不了「我的電子郵件有沒有進過某次資料外洩」。Have I Been Pwned(HIBP)的 Pwned Passwords 範圍查詢是另一條路:本機算 SHA-1,只把雜湊前五碼發給 https://api.pwnedpasswords.com/range/{prefix},完整後綴在用戶端比對。

這篇文章給要把舊密碼拿去「測一測」的開發者、維運,以及被同事丟過來一條「線上密碼檢測」連結的客服。它不代替 密碼檢測 頁的操作說明,也不重複「本地加密有沒有上傳明文」那一套 Network 總論。你要帶走的是:三種查法分別離開本機什麼、本機名單涵蓋到哪一步變形、命中和未命中各自能寫進工單的哪一句。

三種「查外洩」不是一回事

搜尋「密碼外洩查詢」時,結果頁會把完全不同的協定排在一起。有的網站把輸入框裡的字元直接 POST 出去;有的接入 HIBP 的 k-anonymity 範圍 API;有的只下載一份短名單,在瀏覽器裡做字典查詢。三種都能在畫面上顯示「未發現」或「已外洩」,但請求列完全不同,能支持的結論也不同。

OWASP Authentication Cheat Sheet 把「擋下常見和已外洩密碼」寫成註冊與變更密碼流程的建議,並同時點名 Pwned Passwords 與 SecLists 一類公開清單。它沒有把「本機短名單」和「十億級雜湊庫」寫成同一種證據。工單裡若只寫「查過了,沒外洩」,接收方無法判斷你用的是哪一張網。

做法 離開本機的是什麼 未命中能寫什麼
明文或完整雜湊上傳 密碼本身,或足以還原/比對的完整摘要 只證明對方網站這次沒標紅;證明不了安全
HIBP 範圍查詢 SHA-1 或 NTLM 的前 5 碼十六進位 在 HIBP 目前索引裡沒找到這串雜湊
本機公開高頻名單 名單檔案本身;待測密碼留在分頁 這份短名單及其變形規則沒對上

第三種的網路活動仍然存在:瀏覽器會 GET 名單檔案。那是公開詞表,不是你的密碼。把這兩種請求當成「都連網了所以都上傳了」,會誤判界線;反過來,把「頁面寫了本地」當成證據,也會漏掉第一種網站。

不要用正在使用的正式環境密碼、尚未輪替的 API Token 或個人網路銀行密碼做實驗。準備一串只有這次才有的假密碼當金絲雀,例如 CanaryPwd-20260902-xK9。核對的是請求有沒有帶走這串字元,不是把真實秘密再暴露一遍。

本機名單實際對照什麼

以 FastPwd 密碼檢測頁為例,名單隨頁面從同源路徑 data/leaked-top10k.txt 下載,再在本機建一張小寫鍵到名次的表。檔名帶 top10k,是常見公開高頻清單的命名習慣;開啟該請求的回應,目前能數到八百多筆非空行,開頭是 123456、password、qwerty 這類被反覆外洩的密碼。產品文案從不把它寫成「一萬筆」或「全網外洩集合」。

查詢不是只做一次完全相等比較。實作裡按四步走,命中任一步就標紅,並強制把等級打成弱。

  1. 精確比對:輸入與名單條目完全一致。
  2. 大小寫摺疊:先轉成小寫再查,Password 與 password 同一筆。
  3. 去掉尾部 0–999:qwerty123 會先被收成 qwerty 再查。
  4. 常見 Leet:@/4→a,3→e,1/!→i,0→o,5/$→s,7→t;也可先去尾部數字再做這一步。

輸入超過 128 字元時,後兩步變形不再跑,只保留精確與大小寫。名單載入失敗時,頁面會改用內建最小集:password、123456、12345678、qwerty、admin123,並在狀態列說明檢測仍在本機完成。名次只用來寫提示:前 100、前 500、前 1000,或退回「公開外洩名單」——它不是 HIBP 那種「出現過多少次」的計數。

NIST SP 800-63B-4 要求驗證端在開戶和變更密碼時,把候選密碼整串對照「常見、可預期或已外洩」的黑名單,而不是對照子字串;同時寫明不應再疊一套組成規則。本機高頻名單符合「先擋住最常被猜的那一批」這一層,但名單規模遠小於攻擊者手上的完整字典,也遠小於 HIBP 持續併入的外洩雜湊。2026 年 6 月,HIBP 僅 June 2026 Stealer Logs 這一批就寫入了約 1.24 億個不重複密碼。八百多筆公開高頻詞能抓住 123456,抓不住只在某一次企業內部資料外洩裡出現過的長密碼。

HIBP 範圍查詢送什麼、不送什麼

HIBP 的密碼頁自己寫著:沒查到「並不一定代表這是好密碼,只代表它不在本站索引裡」。範圍查詢的協定寫在 API v3 · Pwned Passwords。用戶端先對密碼做 SHA-1(或依 mode=ntlm 做 NTLM),取出前 5 個十六進位字元,請求 GET https://api.pwnedpasswords.com/range/{prefix}。伺服器端回傳該前綴下的全部後綴和出現次數;完整 40 碼雜湊的後 35 碼留在本機比對。

官方給出的規模可以當場對照:一次範圍查詢通常回傳大約 800 筆後綴;前綴空間是 165 = 1,048,576 個,從 00000 到 FFFFF,每一個都回 HTTP 200,不該出現 404。可選請求頭 Add-Padding: true 會把回應補到 800–1000 行,降低旁觀者靠回應長度反推前綴的能力。Cloudflare 在 Validating Leaked Passwords with k-Anonymity 裡把這套範圍查詢稱為 k-匿名:伺服器端拿不到未外洩密碼的完整雜湊,因此也無法事後單獨「解開」這一次查詢。

電子郵件查詢是另一條路。官方寫明:把電子郵件直接放進 URL 路徑會把該地址交給 HIBP;若要用 k-anonymity 查電子郵件,送的是電子郵件 SHA-1 的前 6 碼,不是密碼的前 5 碼。把「我在 HIBP 查過了」寫進工單時,要寫清查的是密碼雜湊前綴,還是電子郵件。兩者的隱私界線不同,結論也不同。

FastPwd 不呼叫上述任何一個 HIBP API。密碼檢測頁能做的是本機熵估算加這份公開高頻名單。需要對照十億級雜湊庫時,應使用 HIBP 官方頁面或自行建置離線副本,並自己開啟 Network 確認請求列只有五碼前綴。不要預設以為「安全工具都會幫你查 HIBP」。

用 Network 當場核對待測密碼有沒有離站

頁面上的「不上傳」不能當證據。金絲雀字串可以。步驟與「本地加密有沒有帶走明文」同類,但觀察目標改成密碼欄位和名單檔案。

  1. 開啟開發者工具 Network,勾選 Preserve log。篩選先留空,避免漏掉分析上報。
  2. 在密碼檢測頁輸入金絲雀,例如 CanaryPwd-20260902-xK9,等大約 280 毫秒後的本機計算結束。
  3. 在請求清單裡搜這份金絲雀:請求列、Query、請求主體、表單欄位都不該出現它。
  4. 應該能看到一次同源 GET data/leaked-top10k.txt。開啟回應,確認是一行一筆公開密碼,沒有你剛輸入的金絲雀。
  5. 若網站宣稱有接 HIBP,另外找 api.pwnedpasswords.com/range/:路徑裡只該有五碼十六進位,不該出現明文。

造訪統計可以存在。FastPwd 的檢測追蹤只送事件名稱,例如「开始审计」「结果弱」「命中泄露列表」,不把輸入框內容當成參數。在 Network 裡開啟指向 /tj/matomo.php 的上報,搜尋金絲雀,應該沒有命中。關閉分頁後,這次輸入不會留在 FastPwd 伺服器上——前提是它從未當成業務資料到達伺服器。這一點要用剛才的搜尋來支持,不能用「我關頁面了」來支持。

若金絲雀出現在任何請求裡,結論就翻轉:無論按鈕寫「本地」還是「隱私」,這一次檢測已經把密碼送出分頁。換工具,或改用離線名單,再重複同一步驟。

命中和未命中分別能支持什麼

命中時,工單裡可以寫實的句子是:「這串字元與隨頁面下載的公開高頻名單在某一步對上了(精確/大小寫/尾部數字/Leet),依本機規則視為極常見弱密碼,必須更換,且不要在其他網站重複使用。」不能寫的是:「對方伺服器確認這是某年某次資料外洩的原文。」本機名單沒有事件名稱、沒有出現次數,只有名次提示。

未命中時,能寫的更短:「在目前這份公開高頻名單及其四步變形下未命中。」不能寫:「從未外洩」「可以繼續用」「比 HIBP 更乾淨」。一份八百多筆的高頻表,本來就不是為了「證明安全」而設計的。攻擊者的噴灑字典、公司內部歷史密碼、只在一次私下外洩裡出現的長句,都不會出現在這張表裡。

熵估算是第三條平行資訊。頁面依長度和字元類估算 bits:≥ 80 為極強,≥ 60 為強,≥ 40 為中,其餘為弱;離線窮舉依大約每秒 100 億次、線上限速依大約每秒 1000 次給出時間量級。長度不足 8 字元或命中內建 Top 常見弱密碼時,等級會被壓到弱。這些數字用來比較相對強弱,不是倒數計時承諾。命中公開名單時,熵再高也會被改寫成弱——因為字典攻擊不走「平均窮舉」這條路。

常見問題

未命中弱密碼名單,是不是代表密碼從沒外洩過?

不是。未命中只代表:在目前分頁這份公開高頻名單裡,精確比對、大小寫摺疊、去掉尾部 0–999、常見 Leet 這幾步都沒對上。它不能證明這串字元從未出現在任何一次資料外洩、未出現在 Have I Been Pwned,也不能證明可以繼續重複使用。

Have I Been Pwned 查密碼會不會把明文送出去?

依官方 API:Pwned Passwords 範圍查詢只接收 SHA-1 或 NTLM 雜湊的前 5 碼,回傳約 800 筆後綴,完整比對留在用戶端。明文和完整雜湊都不應出現在請求裡。用電子郵件查外洩是另一套 API,直接送出電子郵件會把該地址交給對方。以你開啟 Network 看到的那一列為準,不以按鈕文案為準。

FastPwd 的密碼檢測會不會查詢 Have I Been Pwned?

不會。對照的是隨頁面下載到本機的公開高頻名單。待測密碼不當成 HTTP 業務資料送出,也不寫入 analytics。造訪統計只記「开始审计」「结果弱/中/强」這類事件名稱。開啟即用,無需帳號,站內也沒有密碼庫可保存檢測紀錄。

熵很高但命中名單,到底算不算強密碼?

依本機規則,命中公開弱密碼名單會強制標為弱。熵估算的是字元空間上的窮舉成本,名單回答的是「攻擊者字典裡有沒有這串」。兩套問題不能互相抵消。NIST SP 800-63B-4 要求驗證端對照常見或已外洩密碼的整串黑名單,而不是只看複雜度或定期更換。

用假密碼把步驟走完

若你希望用一個把計算界線寫清楚的頁面來練習,開啟 FastPwd 的 密碼檢測。開啟即用,無需註冊。先輸入 password 或 qwerty123,應該看到命中公開名單並強制為弱;再輸入上面的金絲雀,應該未命中名單,同時 Network 裡搜不到這串字元。名單檔案那一次 GET 可以開啟來數行數,和本文寫的「八百多筆高頻詞」對齊。

判定為弱之後,到 密碼產生器 在本機抽出一組新密碼:亂數模式長度 6–128 字元,預設 16 字元,低於 8 字元會提示安全性較低。必須把新密碼交給同事時,改走 閱後即焚:本機用 AES-256-GCM 加密,伺服器只暫存密文,金鑰放在連結的井號後面。不要把完整閱後即焚連結再貼回任何一個「線上檢測」輸入框。

這些練習的目的不是證明某一個網站「絕對安全」,而是讓你在按下檢測之前,手上有一份可以給同事看的對照:這一次走的是明文上傳、雜湊前綴,還是本機短名單;命中時換掉,未命中時不要寫成「從未外洩」。換成任何「安全評分」或「外洩查詢」擴充功能,步驟可以沿用。

下次有人把密碼丟進檢測框時,先問三個問題。第一,請求裡有沒有明文或完整雜湊。第二,對照的是八百多筆高頻詞,還是 HIBP 那種範圍查詢。第三,未命中時工單打算寫哪一句。能重複做的對照,才值得寫進你們自己的密碼規範。

延伸閱讀

若還要確認「檢測頁自己有沒有把原文送走」,用同一枚金絲雀走完更完整的 Network 步驟:瀏覽器本地加密怎麼核對明文沒有離開本機。必須把完整秘密交給另一個人、而不是交給檢測框時,再看金鑰為什麼能放在井號後面:URL 的井號後面為什麼適合放金鑰,以及什麼時候會失效。工單和日誌要貼進 AI 之前,欄位級對照見:把工單和日誌貼進 AI 之前,怎麼先核對哪些欄位會離開本機。