随机密码生成器

勾选需要的字符类别和长度,一次抽出若干条通用随机密码,每条右侧附带一条 5 格强度条,结果可以整体导出成 CSV。

字符类别与规则
示例展示(演示值,点「生成密码」后才会替换为真机随机结果):
Kd7nMq2WszTp
hR4vXc9byLjm
tG6pQw3nZkrV
#密码十进制位数 d强度条

长度或数量框里按 Enter 直接生成;同一组设置下每条的强度档位完全相同,因为档位只由字符池和长度决定,和这一条具体抽到哪些字符无关。

使用方法

  1. 「密码长度」默认填 12(示例值),允许 8~64 之间的整数;「生成数量」默认填 15(示例值),允许 1~50 条。
  2. 字符类别默认勾选 大写字母、小写字母、数字 三类,符号默认不勾——部分企业内网登录页、路由器管理页和 POS 终端键盘对 ! # % & 的输入处理不一致,默认关掉能少踩一次坑。
  3. 保持「剔除相似字符 0Oo1Il」勾选,字符池会由 62 位降到 56 位,10 位十进制以下的信息量损失在第 3 节有具体数字。
  4. 点「生成密码」,或直接在长度、数量输入框里按 Enter。结果表每一行右侧会出现一条 5 格强度条,格数越多档位越高。
  5. 结果表默认先显示 12 行,点「加载更多」每次追加 12 行;需要带走时用「复制全部」(一行一条密码)、「导出 CSV」(带 BOM,Excel 打开中文不乱码)或「复制对照表」(制表符分隔,可直接粘进表格)。

这个随机密码生成器能解决什么问题

一是默认值直接可用。很多工具默认把四类字符全勾上,生成的密码里带 *、^,粘进只接受字母数字的旧系统里直接报错。本页默认只开三类字符,需要符号时自己勾,少一次「生成—被拒—改设置—再生成」的来回。

二是一次拿到一批,且每条都满足类别要求。生成时先给每个已勾选的类别各抽一个字符,再用整个字符池补足长度,最后整体洗牌。这样抽出来的每一条都天然含大写、小写、数字各至少一个,不会被「密码必须同时包含字母和数字」这类注册校验打回。

三是把「这条密码到底算不算强」变成看得见的东西。结果表右侧的强度条把 5 个档位画在一行里,同一批密码一眼扫过去就知道当前设置落在哪一档;调长度、加类别时条子会当场伸长,比记住一串 bit 数直观。

四是方便把结果搬进别的地方。给一批设备写初始口令、给测试库造账号、给 CSV 批量导入准备凭据时,用「导出 CSV」拿到带 BOM 的表格文件,或者用「复制对照表」把整张表贴进 Excel,不用一条条选中复制。

本页不做这些事:不保存密码(不写 localStorage、不发任何网络请求)、不去查这条密码有没有出现在历史泄露库里、也不做「密码短语」那种用常见单词拼长口令的事。想评估一条已有密码的强弱,请用页面底部的「密码力量检测」。

生成原理:字符类别、字符池与拒绝采样

1)随机数从哪来。取值只有一行:crypto.getRandomValues(new Uint32Array(1))。它是 W3C Web Cryptography API 定义的加密随机接口,由浏览器直接向操作系统熵池要数,不是 Math.random() 那种内部状态可推导的伪随机序列。RFC 4086《Randomness Requirements for Security》给出的结论是安全凭据必须建立在不可预测的随机源上,用时间戳、进程号、自增计数器拼出来的「随机」在攻击者眼里基本等于可枚举。全站 2000 多个工具里,只有生成凭据的页面必须走这个接口。

2)为什么必须做拒绝采样。拿到一个 32 位无符号整数后,最省事的写法是 n % 池大小。但当池是 56 位时,2³² = 4294967296 不能被 56 整除:4294967296 ÷ 56 = 76695844 余 32。余数落在 0~31 的随机数比落在 32~55 的多出现一次,一些字符被抽中的概率会高出约 32 / 4294967296 = 7.45×10⁻⁹ 的相对偏差——数值很小,但它是结构性偏差,不会因为抽得多而消失。本工具的做法是先算出接受上限 Math.floor(4294967296 / 56) × 56 = 4294967264,随机数一旦落在 4294967264~4294967295 这 32 个值上就丢弃重抽。

3)为什么用 32 位而不是 8 位字。拒绝率和字宽直接相关。同样池 56 位,改用 Uint8Array 时接受上限是 256 − (256 % 56) = 224,要丢掉 32 个取值,拒绝率高达 12.5%,等于每 8 次取数就有 1 次白跑;换成 32 位字后丢弃比例降到 7.45×10⁻⁹,肉眼完全看不出停顿。池换成 62 位(不剔除相似字符)时,单字节方案的拒绝率也有 3.125%,32 位方案则是 9.31×10⁻¹⁰。

4)字符池怎么算出来的。大写字母 26 个、小写字母 26 个、数字 10 个、常用符号 12 个(!@#$%^&*_-+=)。「剔除相似字符」会从池里去掉 0 O o 1 I l 这 6 个字符,其中大写贡献 O I、小写贡献 o l、数字贡献 0 1,符号集里一个都没有。所以默认三类字符是 26 + 26 + 10 = 62 位,剔除后 56 位;四类全勾是 74 位,剔除后 68 位。

5)强度条怎么分档。把取值空间写成十进制,位数记为 d,取 d = floor(长度 × log₁₀(字符池))——也就是「猜中需要试多少个十进制的数」。池 56 位时 log₁₀56 = 1.748188,长度 12 位对应 d = floor(12 × 1.748188) = floor(20.9783) = 20。分档阈值取 8 / 12 / 16 / 24 四个整数关口:d 小于 8 判 1 格「弱」,8 到 11 判 2 格「一般」,12 到 15 判 3 格「强」,16 到 23 判 4 格「很强」,24 及以上判 5 格「极强」。这四个关口对应的是「秒级可穷举」「小时内可穷举」「需要专门算力」「需要大型集群」四道台阶,而不是随手切的等分。

6)洗牌用的是 Fisher–Yates。先把每个类别的强制位放进数组,补足长度后整体洗牌,从末位往前遍历、与前面随机一位交换。常见写法 sort(() => Math.random() - 0.5) 在多数 JS 引擎里会因为比较函数不满足传递性而退化成偏差明显的伪洗牌——如果用它,强制位就容易扎堆在开头,密码的形态一眼可辨。

完整示例(默认设置,数值仅作演示)

下面这套条件就是这个随机密码生成器打开时的默认值:长度 12 位、数量 15 条、勾选大写字母 + 小写字母 + 数字、勾选剔除相似字符,字符池 56 位。

把长度从 12 位调到 16 位,d 立刻从 20 跳到 27,强度条从 4 格涨到 5 格;再把长度调回 8 位,d 掉到 13,条子只剩 3 格。这条条子跟的就是长度 × 字符池,不看具体字符——它衡量的是「猜中的难度」,衡量不了「这条密码会不会被钓鱼页骗走」。

字符类别与长度对照表

下表固定长度为 12 位,逐档改变勾选的字符类别,用来回答「少勾一类会掉多少」:

勾选的字符类别(长度固定 12 位)字符池取值空间d强度档位
只勾「数字」8 位6.87×10¹⁰10一般(2/5)
只勾「小写字母」24 位3.65×10¹⁶16很强(4/5)
勾「大写 + 小写」48 位1.50×10²⁰20很强(4/5)
勾「大写 + 小写 + 数字」(默认)56 位9.51×10²⁰20很强(4/5)
四类全勾(含常用符号)68 位9.77×10²¹21很强(4/5)

再看固定字符池 56 位、只改长度的那张表。它说明一件事:加长度比加字符类别划算得多——从 12 位加到 16 位,d 涨 7;把字符从三类加到四类,d 只涨 1。

密码长度(池固定 56 位)取值空间d强度档位每秒 10¹² 次穷举一半
8 位9.67×10¹³13强(3/5)48.4 秒
10 位3.03×10¹⁷17很强(4/5)1.8 天
12 位(默认)9.51×10²⁰20很强(4/5)15.1 年
16 位9.35×10²⁷27极强(5/5)1.48×10⁸ 年
20 位9.20×10³⁴34极强(5/5)1.46×10¹⁵ 年
24 位9.05×10⁴¹41极强(5/5)1.43×10²² 年

第三张表是拒绝采样的取舍,说明为什么代码里用的是 32 位字而不是单字节:

字符池单字节 Uint8Array 接受上限单字节拒绝率32 位字接受上限32 位字拒绝率
56 位(默认)22412.5%42949672647.45×10⁻⁹
62 位(不剔除相似字符)2483.125%42949672929.31×10⁻¹⁰
68 位(四类全勾并剔除)20420.313%42949672441.21×10⁻⁸

输入范围、边界与强度条档位说明

下面这些不是随便定的限制,知道它们能避免把这页当万能工具用:

常见问题

为什么默认不勾「常用符号」?

因为大部分密码用在登录框里,而符号在不少终端上会被「吃掉」——POS 机键盘、路由器管理页的旧版输入框、部分企业 SSO 页面会把 & 或 # 当成转义字符。默认关掉符号、需要时自己勾,比生成完才发现登不上去再回来改要省事。真要高强度账号,加长度比加符号划算:池从 56 涨到 68,d 只涨 1。

生成的密码会重复吗?点两次会不会拿到同一批?

12 位默认设置下两条完全相同的概率约为 1 / 9.51×10²⁰;一批 15 条里任意两条撞车的概率约 1.10×10⁻¹⁹,实际可以认为不会重复。每次点按钮都是一次全新的抽取,工具不缓存上一次的结果,所以前后两批之间同样不会互相干扰。

为什么剔除相似字符只让字符池少了 6 位,强度条却几乎不动?

因为 d 是对数尺度。池从 62 位降到 56 位,单字符的信息量从 log₂62 = 5.954 bit 落到 log₂56 = 5.807 bit,每位差 0.147 bit;12 位一共少 1.76 bit。换成十进制位数只是从 21 位降到 20 位,两个都落在「很强」区间,所以条子的格数不变。剔除相似字符买到的是人工抄写不易出错,代价小到可以忽略。

强度条的五个档位是按什么切的?

按十进制位数 d:小于 8 是「弱」(1 格),8~11 是「一般」(2 格),12~15 是「强」(3 格),16~23 是「很强」(4 格),24 及以上是「极强」(5 格)。四个关口分别对应「一台笔记本秒级穷举」「小时内穷举」「需要 GPU 集群」「需要国家级算力」。切法是按穷举成本的数量级定的,不是等分。

「每类至少出现一次」是怎么做到的?

生成一条密码分两步:先按你勾选的每一个类别各抽一个字符放进数组(保证类别齐全),再用整个字符池补足到指定长度,最后用 Fisher–Yates 把整个数组洗一遍。洗牌这一步很关键——如果省略它,每个类别的那个「代表字符」会一直待在数组开头,密码的形态一眼就能看出来。

导出的 CSV 和「复制对照表」有什么区别?

两者内容一样(序号、密码、十进制位数、强度档位),差别在编码和分隔符。CSV 是文件,编码 UTF-8 并加了 BOM,Excel 双击打开不乱码,字段用逗号分隔;「复制对照表」走剪贴板,用制表符分隔且不带 BOM,适合直接粘进已经打开的表格或数据库客户端。密码里不含逗号和制表符,所以两种格式都不会串列。

可以用它生成接口 token、临时口令吗?

可以,但要注意 token 的字符集限制。URL 里用的 token 如果混进 + / = 这些字符,放到 query string 里需要额外做百分号编码,否则会被截断。这类场景建议只勾「大写字母 + 小写字母 + 数字」,再把长度提到 32 位,得到的就是纯字母数字串,任何传输层都不用再转义。

页面会把生成的密码上传或保存下来吗?

不会。随机数由 crypto.getRandomValues 提供,拼接、剔字符、洗牌、渲染全在当前页面完成,没有任何网络请求;也没有写 localStorage 或 sessionStorage,刷新即丢。想自己验证,打开开发者工具的 Network 面板,点几次「生成密码」,看不到任何新请求发出。

相关工具