換工作、開新站、把舊密碼改成「再加一個驚嘆號」之前,很多人會先搜一遍:這組密碼有沒有外洩。搜尋結果裡,「密碼強度檢測」「Have I Been Pwned」「線上外洩查詢」常常排在一起,標題都像在回答同一句。點進去之後,有的頁把輸入框內容 POST 到自己的伺服器,有的只向第三方介面要一份雜湊後綴清單,有的只下載一份公開弱密碼詞表,在分頁裡比對。三種流程對「有沒有把密碼送出去」的答案完全不同。
本文不複述某個檢測頁能打出弱、中、強,也不教你去撞別人的資料庫。問題只有一個:本機對照一份公開名單,和把密碼交給全網查詢,分別能證明什麼、不能證明什麼。MyPassGen 的密碼檢測屬於前者:待測密碼不上傳,對照的是隨頁載入的公開弱密碼名單,開啟即可使用。下面把界線攤開,並用開發者工具當場核對。
三種完全不同的「查密碼」
先把名字對齊。否則「本地」「不上傳」「查過外洩庫」可以同時出現在行銷句裡,卻指向三套協定。
| 做法 | 離開瀏覽器的是什麼 | 能回答的問題 |
|---|---|---|
| 把密碼原文交給網站 | 明文,或可還原的表單欄位 | 對方伺服器說「查過了」——你看不見依據 |
| k-匿名範圍查詢(如 HIBP) | SHA-1 或 NTLM 雜湊的前 5 個十六進位字元 | 這個雜湊有沒有出現在對方維護的全庫裡 |
| 本機對照公開弱密碼名單 | 一份靜態詞表檔,不是你的輸入 | 是不是「123456」「password」這類已被反覆使用的密碼 |
第一類最省事,也最難核對。頁面可以寫「查詢後立即刪除」,紀錄、備份和分析腳本仍可能留下副本。第二類是 Have I Been Pwned Pwned Passwords 公開說明的做法:瀏覽器先算雜湊,只把前綴發給 api.pwnedpasswords.com/range/{prefix},後綴清單拉回來再在本機比對。第三類連前綴都不送。詞表是公開的常見弱密碼,體量通常是幾百到一萬條,不是「全網每一次資料外洩」。
美國國家標準與技術研究院在 NIST SP 800-63B-4 裡要求驗證方在設立或更換密碼時,對照一份「常用、可預期或已外洩」的黑名單,並且不要再疊加強制大小寫、數字、符號組合規則。它同時寫明:黑名單的主要用途是擋住線上猜測裡最容易先試的那些;名單大到超過速率限制視窗,增量收益很小。這正好解釋了本機 Top 名單的位置:它是攔截常見弱密碼的第一道篩,不是全網檔案檢索。
先分清問題,再選工具
「會不會被字典先猜中」和「有沒有出現在某一次具體的資料外洩」不是同一句。本機名單回答前一句;全庫範圍查詢回答後一句裡「對方這份庫收不收得到」。兩者都不能代替:不要在多個網站重複使用同一組密碼。
把原文交給網站意味著什麼
仍有一批「線上密碼檢測」把輸入框裡的字串直接放進請求主體。有的寫成 JSON 欄位 password,有的放進查詢字串,有的先做一層可逆編碼再 POST。對瀏覽器來說,這和登入表單沒有本質差別:對端主機、反向代理和存取紀錄都能看見這一次提交。
HTTPS 只保護傳輸路徑上的竊聽者。它不禁止對端把明文寫入磁碟,也不禁止分析腳本把欄位再轉發出去。你要減少的是這一次檢測有沒有多一個知情者,不是改寫 HTTPS 的職責。上一篇瀏覽器裡做加密怎麼當場核對已經寫過同一條原則:口號無法證明,流量可以。
還有一種更隱蔽的交出去法:把待測密碼寫進網址列的查詢參數,再把連結轉寄給同事或丟進工單。查詢字串會進入請求列,也會進對端紀錄;部分第三方資源的 Referer 仍可能帶上路徑和 query。檢測用的密碼如果是真實帳戶密碼,這一步等於主動擴散。正確的預設是:真實密碼只留在目前分頁的輸入框裡,不要寫進網址,也不要貼進會上傳原文的「檢測站」。
只送雜湊前綴的全庫查詢
Have I Been Pwned 的範圍介面把「全庫」和「不交原文」拆開。官方文件寫的步驟是:在本地把密碼編成 UTF-8,算 SHA-1(也可選 NTLM),取出雜湊的前 5 個十六進位字元,請求 GET https://api.pwnedpasswords.com/range/{前五位}。回應是一批後綴加出現次數,用冒號分隔;用戶端在本機把前綴和後綴拼回去,看有沒有整段命中。Troy Hunt 在 Understanding Have I Been Pwned's Use of SHA-1 and k-Anonymity 裡把這種模型稱為 k-匿名:伺服器看見的是一個雜湊桶,不是完整雜湊,更不是密碼原文。
Cloudflare 與 HIBP 合作時公開過一組可核對的數字:前綴取 5 位時,同一桶裡雜湊數量的中位數大約是 305,回應體積中位數大約 12.2 KB。官方還提供 Add-Padding: true:把每條回應填補到約 800–1000 行,降低「看回應有多長就能猜你查的是哪一類常見密碼」的旁路。這些都說明:範圍查詢比把原文 POST 出去克制得多,但它仍然是一次對外請求。Network 裡會出現對 api.pwnedpasswords.com 的存取;中斷網路,這類查詢應當失敗。
範圍查詢也不是「絕對匿名」。前綴會告訴觀察者你的雜湊落在哪一個 165 分桶裡;頁面腳本如果在送前綴之前就把原文另存一份,k-匿名幫不上忙。電子郵件檢索和密碼檢索還不是同一條 API:依 HIBP v3,電子郵件的雜湊範圍查詢用的是前 6 位,而且那是另一套產品能力。本文只對照「查這組密碼有沒有出現在密碼庫」,不把信箱訂閱、網域監控寫成同一件事。
因此,把「用了 HIBP」寫成「密碼完全沒離開裝置」並不準確。準確說法是:原文和完整雜湊依設計不發給對方;前綴和一次範圍請求會離開。你若接受「讓一家維護全庫的第三方知道雜湊桶」,這是合理的工程折衷。你若要求「這一次檢測連前綴都不出站」,就應走下一節的本機名單,並承認涵蓋範圍更窄。
本機名單只拉詞表,不交密碼
本機對照的流程反過來:先把一份公開弱密碼列表下載到目前來源,再在腳本裡做集合查找。Network 裡允許出現詞表檔,不允許出現輸入框裡的待測密碼。詞表本身是公開資料,常見來源包括 OWASP / Daniel Miessler 維護的 SecLists 裡「一千萬密碼擷取 Top N」那一類檔案。它回答的是「攻擊者字典會不會先試到你」,不是「某一次未公開的資料外洩裡有沒有你」。
MyPassGen 按這個界線做檢測。頁面開啟後會請求 data/leaked-top10k.txt:目前約 860 行,每行一條小寫密碼,開頭是 123456、password、qwerty 這類反覆出現的弱密碼。比對在瀏覽器裡完成:先轉成小寫,再產生有限變體——把 @ / 4 看成 a、0 看成 o 等常見 leet,以及去掉結尾一到三位數字——再看是否落在集合裡。命中即標為弱,哪怕看起來「很長」。詞表載入失敗時,腳本退回內建的最小集合(password、123456 等),而不是改去請求外部外洩介面。
強度評估是另一條本地計算。字元集依是否含小寫、大寫、數字、符號累加(26 + 26 + 10 + 32),熵近似為長度乘以 log2(字元集),重複字元過多會再打折。分級門檻是:約 40 bits 以下為弱,60 以下為中,80 以下為強,以上為極強。長度不足 8 位會另外提示較弱;隨機產生器允許 6–128 位,預設 16 位。離線暴力破解按每秒 1010 次猜測估算,線上速率限制按每秒 103 次——這是給自己看的數量級,不是對某張顯示卡的承諾。分析事件只記等級和是否命中名單,不把密碼原文送進統計。
這些數字你可以在本機對上:詞表行數用編輯器或 wc -l 就能數;Network 裡應看到詞表,不應看到輸入。它仍然不能寫成「查過全網」。860 條連 SecLists 公開的 Top 10,000 都沒有覆蓋完,更不要說 HIBP 那種按雜湊收錄的完整密碼庫。沒命中的唯一誠實結論是:它不是這份名單裡的常見弱密碼。
名單沒命中,不要寫成「安全」或「從未外洩」
本機名單攔的是字典最前面那一批。你的密碼完全可能出現在名單之外的資料外洩、撞庫組合或針對你網站的社交工程猜測裡。需要換新密碼時,在本機產生一條,不要在原字串後面加西元年或驚嘆號繼續重複使用。
強度條證明不了沒外洩
強度條估算的是窮舉空間,不是檔案檢索。一條 20 位隨機密碼的熵可以很高,一旦它已經出現在別人的外洩檔案裡,攻擊者不會按字元集從頭猜,會直接拿現成清單去撞。反過來說,Password1! 往往能騙過「必須有大小寫、數字、符號」的表單,卻幾乎總會落進公開弱密碼名單。NIST 之所以不再要求組合規則,依據就是這類繞過手法太常見。
所以檢測頁若同時給出強度和名單結果,應以名單為準蓋過強度:命中即弱。強度條仍有用,它提醒你「太短、只有一類字元、含 qwerty 鍵盤序列」。它不能單獨簽發「可以繼續用」的證明。你要的決策通常是兩句:命中名單或短於 8 位——立刻換;沒命中且夠長——仍然不要跨站重複使用,重要帳戶優先用密碼管理器或本機產生器另外寫一條。
「全網查詢顯示沒中」同樣不是終點。範圍查詢依賴對方庫的收錄範圍與更新節奏;庫外的未公開外洩、內部系統密碼、尚未被雜湊收錄的變體,都不會出現。它比本機 860 條廣得多,也仍是一份他人維護的樣本。兩種工具疊在一起用可以,前提是你分得清各自的離站內容和失敗代表什麼。
當場核對:詞表可以有,密碼不能有
下面這組步驟不依賴品牌承諾。用一條可丟棄的測試密碼,例如 password 或你從未在任何帳戶用過的臨時字串。不要把正在使用的真實密碼貼進示範。
- 打開開發者工具的 Network,勾選「保留記錄 / Preserve log」。篩選先選 Fetch / XHR,再掃一遍文件與其他請求。
- 重新整理檢測頁。應看到一份靜態名單(本站是
leaked-top10k.txt)。點開該請求:回應是一行一條密碼,請求主體應為空。 - 在輸入框輸入測試密碼,等結果出現。再看新增加的請求:網址、query、JSON、表單欄位裡都不應出現剛才輸入的那串字元。
- 搜尋面板裡的
pwnedpasswords、hibp、range/。本機名單方案不應出現這些主機;若出現,說明頁面走了範圍查詢,應改用上一節的標準理解它。 - 再掃分析請求(常見路徑含
matomo、collect)。事件名稱可以有「弱 / 中 / 強」,值裡不應有密碼原文。 - 需要對照「全庫方案」時,用同一條可丟棄密碼在會呼叫 HIBP 的頁面測一次:應看到對
api.pwnedpasswords.com/range/的 GET,路徑只有 5 個十六進位字元,沒有原文。
中斷網路再輸入一次,是本機方案的加分核對:詞表若已快取,強度和命中仍應能算;範圍查詢應失敗。不要把「完全無請求」當成唯一及格線——第一次開啟必須把詞表下載下來,這和把密碼 POST 出去不是同一類流量。上一篇講本地加密時用過同一套面板;這裡只多盯一件事:業務請求裡有沒有你的輸入。
誤區:綠條、全網,以及「查過就安全」
「強度條是綠的就沒外洩」不成立。綠條描述的是字元空間,外洩描述的是別人是否已經拿著同一串字。兩件事可以同時成立。
「寫了本地計算就等於沒出站」也不成立。本機名單會下載詞表;範圍查詢會下載某個雜湊桶。你要禁止的是原文和完整雜湊當業務資料離開,不是禁止一切 HTTP。
「沒出現在 HIBP 就可以在所有網站重複使用」是代價最高的誤區。憑證填充攻擊用的是「一組密碼打許多站」,不要求這組密碼先出現在公開榜單前一千名。本機名單和全庫查詢都解決不了重複使用。新密碼應在本機產生,長度按隨機模式用夠預設的 16 位或更長,再分別寫進各站。
「把密碼貼進聊天讓同事幫看強不強」把檢測變成了傳播。需要把一條新密碼交給別人時,一次性短密走閱後即焚,金鑰放在網址的 # 後面;需要可反覆解密的檔案走檔案加密盒。檢測頁解決的是「自己先看名單和強度」,不是金鑰交換。
從哪一步開始核對
先測一條你準備淘汰、或從未用於真實帳戶的密碼。開啟檢測頁,看 Network 裡的詞表請求,輸入後再確認沒有把該字串送出。命中名單,就不要再改兩個字元繼續用;到密碼產生器本機產生一條,長度 16 或以上。沒命中,只說明它不是這份公開弱密碼集合裡的成員,仍按網站分開保存。
若你的問題其實是「這組密碼有沒有出現在某一次已知的大規模資料外洩」,本機八百餘條不夠用。應使用會走 k-匿名範圍查詢、並且你能在 Network 裡看到「只送了 5 位前綴」的工具,而不是把原文交給來路不明的查詢頁。兩種核對都做完,仍然記得:開啟即用的檢測不能代替各站自己的登入保護,也不能證明伺服器以後不會再外洩。
做完這一件,你就已經能回答標題裡的差別:本機對照外洩名單,證明的是「像不像攻擊者會先試的那一批」;全網密碼查詢——若實作正確——證明的是「在對方這份雜湊庫裡有沒有整段命中」。前者詞表離站、密碼不離站;後者前綴離站、原文不離站。把原文 POST 出去的第三種,不屬於這兩種。
常見問題
本機沒命中,還要不要去 Have I Been Pwned 查?
取決於你要哪一句答案。沒命中只說明它不是這份公開弱密碼名單裡的成員。若你還想知道它有沒有出現在 HIBP 收錄的密碼雜湊庫,需要另做一次範圍查詢,並在 Network 確認只送了 5 位前綴。兩件事可以分開做,不要混成「已經查過全網」。
範圍查詢會不會把我的密碼告訴 HIBP?
依官方設計和 Troy Hunt 的說明,對方收到的是 SHA-1 或 NTLM 雜湊前 5 位,不是密碼原文,也不是完整雜湊。比對在你的瀏覽器裡完成。它仍是一次對外請求;不接受任何前綴離開裝置時,就只用本機名單,並接受涵蓋範圍更窄。
檢測密碼需要註冊嗎?待測密碼會不會上傳?
不需要註冊。本機方案下,待測密碼應留在輸入框;離開瀏覽器的應是詞表檔,以及不含原文的分析事件。是否做到,以 Network 為準,不以頁面上的「不上傳」為準。
強度裡的「離線要破解 N 年」能信嗎?
那是按固定猜測速率做的數量級提示,不是對某張顯示卡或某個詞表攻擊的測定。名單命中時,攻擊者不會按這個時鐘窮舉。把它當成「太短 / 字元類太少」的參考,不要當成安全保證。