雜記 › 技術筆記 › 一個漢字只算 5 bits:密碼強度評估器的破解時間什麼時候變成宇宙壽命級別

一個漢字只算 5 bits:密碼強度評估器的破解時間什麼時候變成宇宙壽命級別

一、六個漢字只值 30 bits

「密碼強度評估」這六個字是我隨手敲進去的,先入為主覺得它比 8 位隨機小寫字母難猜得多。介面給的是 30 bits、評分 35、「中」;同一頁敲 zqxjvkwm 卻給 37.6 bits、43 分。差別不在長度,在字元集:模板 126-131 行的 charset 只有四個加數——小寫 26、大寫 26、數字 10,121 行那個取反字元類別 /[^a-zA-Z0-9]/ 把漢字、emoji、空格統統塞進 32 這一桶。

於是一個漢字按 log2(32)=5 計費,恰好 5 bits。換成 3500 常用字的外推口徑,6 個漢字應有 70.6 bits,頁面低估了 40.6 bits。

這些數都是在密碼強度評估器裡逐條敲出來抄介面讀數的。另外它不聯網也不查庫:285 行模板裡 fetch、XMLHttpRequest、sendBeacon、localStorage 命中全是 0。

熵 bits:漢字口令的兩種口徑 6 個漢字(模板) 30 6 個漢字(字表) 70.6 8 位純小寫 37.6 12 位四類齊全 78.7 圖 1:分桶把每個漢字定在 5 bits

二、長度按 UTF-16 單元計費

第 134 行取的是 pw.length,不是碼點數。1 個 U+1F600 佔 2 個單元,每單元仍是 5 bits,於是單字元 emoji 顯示 10 bits、18 分、「弱」,3 個相同 emoji 共 6 單元、30 bits、35 分。emoji 沒被特殊照顧,只是長度翻倍多拿 5 bits,字元集那一欄仍是 32。

更要緊的是扣分。第 148 行的連續重複檢測寫的是 (.)\1{2,},對增補平面字元失靈:14 個相同漢字與 7 個相同 emoji 熵都是 70 bits,前者被扣 15 分停在 52「中」,後者拿 67 分進「強」,同一份熵兩個等級。

三、詞典表只有 27 條,命中只動分數

103-108 行那張 commonPasswords 一共 27 條、最長 10 字元。命中一次扣 60 分,156 行的 isCommon 再把等級硬判成「弱」。最扎眼的對照:password 與 xqzmvkdt 熵都是 37.6 bits、線上攻擊都是 33 年,區別只有評分 0 對 43——命中詞典只改分數與文案,熵和破解時間一個數都沒動。

123 行只做 toLowerCase() 全等比對,改一個字元就出表:PASSWORD 照樣命中,而 P@ssw0rd 77 分、password123456 63 分都是「強」。

四、評分封頂 70:熵和等級是兩條線

等級只看 score(156-164 行):低於 30「弱」、30 到 54「中」、55 到 79「強」、80 以上才「極強」。score 在 140-152 行算:長度項 min(40, len×3)、四類字元各 10 分、熵項 min(20, floor(熵/4)),再減詞典 60 分、連續重複 15 分、順序串 15 分。只用一類字元的口令,天花板就是 40+10+20=70,永遠碰不到 80。

口令熵 bits評分等級線上攻擊欄
password(詞典命中)37.60弱33 年
Zq8!(4 位四類齊全)26.258強4 天
1008 位純小寫473870強宇宙壽命級別
Zq8!Km4$vN2&(12 位四類)78.795極強78 萬億年

240 位純數字同樣是 70 分;而表裡 26.2 bits 的 Zq8! 已經算「強」,線上攻擊欄卻只剩 4 天。

五、改口比溢出早幾百個數量級

第 201 行算的是半空間 2^熵/2,除以 195-200 行寫死的四檔速度:線上 100 次/秒、離線慢速 1萬次/秒、離線快速 100億次/秒、GPU 1000億次/秒。列表頁 intro 說的「一般 CPU 約 10 億次/秒」在模板裡沒有對應檔,實測 37.6 bits 的第三行是 10 秒而不是 2 分鐘。後三檔都是離線速度,數量級差見雜湊演算法的速度差那篇。

真正的浮點溢出要熵到 1024 才讓 Math.pow 吐出 Infinity:94 字元集要 157 個字元,32(符號與漢字同桶)要 205、26 要 218;emoji 單元只能取偶數,32 桶要 206 個單元、也就是 103 個碼點。

可 249-263 行的 formatTime 對 Infinity 與 3.1536e+22 秒回的是同一句「宇宙壽命級別」,比較鏈對 Infinity 全部為假,直接落到最後那條 return。94 字元集只要 13 個字元(85.2 bits)線上欄就這麼寫了,此時慢速欄還剩 70 萬億年;四行改口的長度分別是 13、14、17、18。

字元數:94 字元集口徑 線上欄改口 13 慢速欄改口 14 快速欄改口 17 GPU 欄改口 18 真正溢出 157 圖 2:同一句「宇宙壽命級別」的四行改口長度

單位鏈也有捨入怪癖:閾值依次是 0.001 秒「瞬間」、1 秒「< 1 秒」、60、3600、86400、2592000、31536000,再按年分 1000、1e6、1e9、1e12、1e15,顯示一律 Math.round。於是 31535999 秒顯示「12 個月」,31535999999999 秒顯示「1000 千年」而不是「1 百萬年」。

六、扣分的兩張表對不上

順序字元扣分表在 150 行有 16 條串,改進建議在 223 行只查 4 條。Zxcde1!q 含 cde 與 def,評分從 77 掉到 62,建議區只有「增加密碼長度至12位以上」那句,沒提順序字元;Zsdf9!qq、Z890!qqA 同樣被靜默扣 15 分。連續重複的門檻是 3 個以上:aaa 熵 14.1 bits 只剩 7 分,aa 反而 18 分。

長度那頭反倒全敞開:14 行的 input 沒有 maxlength,1000 個四類字元實測熵 6554.6、評分 100,201 次呼叫的中位耗時 44.6 微秒,20000 字元也只有 582.9 微秒。也沒有批次入口,本地不留紀錄,重新整理就回到 0 分與「—」。想要夠長又夠雜,不如讓強密碼產生器產生一串再來評估。

Q:漢字口令能不能拿這一頁下結論?

不能。它給的是分桶上界,6 個漢字算 30 bits,按 3500 常用字外推是 70.6 bits;等級又被種類分與兩張懲罰表牽制,同一份 70 bits 能給「中」也能給「強」。真正決定難度的是用字規模與撞庫成本,模板都沒查。

Q:看到「宇宙壽命級別」能不能收手?

先分清是哪一欄。94 字元集只要 13 個字元、85.2 bits,線上攻擊欄就打這句,慢速欄此時還剩 70 萬億年;2^熵 真的變成 Infinity 要 157 個字元,兩句文案逐字相同。

Q:改進建議那一欄要不要照做?

參考但別全信。它只查 4 條順序串,扣分表卻有 16 條;也不會告訴你漢字被算進 32 那一桶、emoji 按 2 個單元計費。

📎 相關文章

171! 才溢出,23! 就已經算錯:階乘頁那句「0~1000 不會溢出」的實測邊界 2026-10-27 文字↔ASCII 裡的「ASCII」其實是 UTF-8:1 個漢字吐出 3 個數,無分隔檔 100% 回不去 2026-10-27 它把餘數為 0 的那一行也打給你:GCD 過程展示頁的步數、摺疊順序與 29 步斐波那契 2026-10-27 GIF 縮完尺寸只剩首格:一個檔名叫 .gif 的 PNG 檔案 2026-10-27 BMP 進、PNG 出:12342 位元組的位圖變成 281 位元組,檔名卻還寫著 .bmp 2026-10-27