密碼產生器
在你的裝置上產生。這件事沒有第二種可以接受的做法。
本機處理選好字元集後按下按鈕
完全在你的瀏覽器裡執行 —— 打開開發者工具的 Network 分頁就能驗證
在別人的伺服器上產生的密碼,定義上就是被別人的伺服器看過的密碼。這不是一個要拿來跟便利性權衡的假設性風險 —— 那就是這句話字面上的意思。這一頁完全不發出任何網路請求,而且我們的驗收腳本裡有一條斷言:只要出現一筆請求,驗收就會紅。
在遠端產生密碼到底哪裡不對
值得把問題講精確,因為常見的說法 ——「他們大概不會存吧」—— 完全沒有抓到重點。當伺服器替你產生密碼,那個密碼就存在於那台伺服器的記憶體裡,很可能存在於一筆請求 log 裡,有相當機會存在於一份錯誤報告裡,而且必然經過至少一台你無法掌控的機器。「有沒有人去看」是關於他們的意圖與安全性的問題;「有沒有被暴露」根本不是一個問題。
同樣的推理適用於會回傳資料的瀏覽器擴充功能,也適用於那些去遠端「真隨機服務」取熵的產生器。你自己的機器並沒有隨機短缺到需要做這個交換:每一個現代作業系統都維護一個由硬體播種的熵池,而你的瀏覽器透過 crypto.getRandomValues 直接把它交給你。
這一頁沒有什麼伺服器端可言。它就是靜態 HTML 加 JavaScript;產生發生在你的分頁裡;結果只存在於那裡,直到你把它複製走。十秒就能確認:打開開發者工具切到 Network 分頁,然後想產生幾組密碼就產生幾組,那份清單會一直是空的。這個網站也會送出把連線限制在自己來源的 Content-Security-Policy —— 即使我們的程式想送,你的瀏覽器也會擋下來。
熵值,以及多數產生器算錯的那個算式
熵衡量的是「這個產生器可能產出多少個等機率的密碼」,用位元表示。對於從一個字元池均勻抽出的密碼,它等於長度乘以字元池大小取二為底的對數。從 88 個字元的池抽 20 個字元,略高於 129 位元,遠遠超出任何離線攻擊能觸及的範圍。
很多工具就是在這裡悄悄弄壞了自己的主張。它們幾乎都提供「每一類字元至少一個」,因為網站會硬性要求。常見的實作是:先各放一個,其餘隨機補滿,然後洗牌。這樣的結果在「符合條件的字串集合」上不再是均勻的 —— 某些排列比其他排列更容易出現 —— 於是熵就不是工具報的那個數字,畫面上那個數字高估了它剛剛給你的那組密碼。
這一頁的做法不同。打開這個限制時,是整組候選產生後檢查,不合格就整組重抽。拒絕取樣讓分布嚴格均勻於合法字串集,所以熵就是「合法字串數量」取二為底的對數 —— 而那個數量是用排容原理在各字元類別上精確算出來的,不是估的。你打開限制時,畫面上的數字會掉零點幾個位元,那個下降是真的。一個「加上限制後熵值數字不動」的工具,量的並不是它給你的那組密碼。
長度勝過複雜度,而且差距不小
熵隨長度線性成長,隨字元集大小只是對數成長。在 88 個字元池的 20 位密碼上多加一個字元,大約多 6.5 位元;把池從 88 個加倍到 176 個字元(可列印的 ASCII 根本做不到),才是每個字元多 1 位元。長度才是那根槓桿。
這就是為什麼「大小寫混合、要有數字、要有符號」那套老建議在實務上效果那麼差。它把人推向「很短但塞滿替換」的密碼 —— 難記,卻只是稍微難猜一點,因為攻擊者早就把那些替換規則建模進去了。NIST 現行的指引反映了這件事:最小長度有意義、組成規則不建議、強制定期更換也不建議,因為那會把人推向可預測的遞增。
對於任何你真的得憑記憶打出來的東西,用幾個隨機單詞組成的通關密語在同樣熵值下更好記、也更好抄。其餘的 —— 也就是幾乎全部 —— 請用密碼管理器,讓每一筆看起來就像這一頁的輸出。你反正不會手打它們,所以「記不住」對你完全沒有成本。
易混淆字元,以及為什麼這一頁沒有下載鈕
「避開易混淆字元」會移除大寫 I、小寫 l、數字 1、直線 |、大寫 O、數字 0 與小寫 o。它每個字元付出零點幾位元的熵,換掉一個具體而且很常見的失敗:一組必須從螢幕上唸出來、用電話口述、或從印出來的紙上抄下來的密碼,被抄錯了。一組你打不對的密碼,比一組短了一點點的密碼糟糕得多。
你會發現這一頁沒有下載按鈕,那是刻意的,不是漏做。把剛產生的密碼寫進下載資料夾裡的純文字檔,等於把它放在一個你會忘記的地方、一個很可能被同步到雲端硬碟的地方、以及一個你機器上任何程序都讀得到的地方。請直接複製進密碼管理器。剪貼簿也不是完美的 —— 其他應用程式讀得到,內容也可能留著 —— 所以貼到目的地就好,不要讓它一直待在那裡。
常見問題
密碼真的是在我的裝置上產生的嗎?
是的,而且很容易驗證。打開開發者工具切到 Network 分頁,連續產生幾組密碼 —— 不會出現任何請求。這個網站也會送出把連線限制在自己來源的 Content-Security-Policy,執行它的是你的瀏覽器,跟我們的程式怎麼寫無關。
密碼要多長?
從混合字元池取 16 個字元以上,熵就超過 100 位元,已經在離線攻擊觸及不到的範圍。這裡的預設是 20。如果網站限制長度上限,那個上限才是真正的約束 —— 把它用滿。
「每一類至少一個」會讓密碼變弱嗎?
會非常輕微,因為它排除了一部分原本合法的字串。畫面上的熵值已經算進去了 —— 它是「這個產生器能產生的字串數量」的精確對數,用排容原理算出來。多數產生器一邊強制這條規則、一邊照舊報無限制的數字,那高估了它自己的強度。
為什麼沒有下載選項?
因為放在下載資料夾裡的純文字密碼檔,很可能被忘記、被同步到雲端硬碟,而且你機器上任何程序都讀得到。請改成直接複製進密碼管理器。
破解時間的估算是基於什麼假設?
假設攻擊者拿到密碼雜湊後每秒猜 10^12 次,並且平均在搜尋空間的一半找到答案。那是針對「快速雜湊的離線攻擊」刻意取的悲觀值。線上攻擊會慢好幾個數量級,因為伺服器會限速。
產生過的密碼會被存起來或記錄嗎?
不會。這一頁沒有歷史紀錄 —— 跟擲硬幣和隨機數那兩頁刻意保留累計不同 —— 原因正是「一份產生過的密碼清單」是純粹的風險,沒有任何好處。