杂记 › 技术笔记 › 一个汉字只算 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