令牌生成器

在浏览器中生成密码学强度高的随机令牌、API 密钥、密钥与 nonce。可选择长度、字符集与生成数量。

随机、不可预测的令牌。 所有随机性都来自浏览器的 crypto.getRandomValues,与浏览器生成 TLS 密钥用的是同一来源。数据不会离开你的设备。

什么样的令牌才算安全

随机不等于不可预测

大多数语言都提供两种截然不同的随机数生成器。Math.random()rand() 这一类是速度优先的伪随机生成器,种子往往来自时钟这种廉价来源。用它们打乱播放列表没问题,用来生成令牌则是灾难:攻击者只要观察到少量输出,通常就能还原内部状态,进而复现该生成器今后产生的每一个值。

密码学安全的生成器在设计上保证:看到过去的输出无法推断未来的输出。在浏览器中它就是 crypto.getRandomValues(),数据取自操作系统的熵池。本工具只使用它。如果你要在自己的代码里生成令牌,对应的选择是 Python 的 secrets、Go 的 crypto/rand、Java 的 java.security.SecureRandom——绝不要用普通的 random 模块或 Math.random()

避免取模偏差

拿到高质量随机字节只完成了一半。最直觉的取字符方式是 bytes[i] % alphabet.length,但只要字母表大小不能整除 256,结果就会悄悄偏斜。以 62 字符的字母表为例,前 8 个字符出现的概率会略高于其余字符——偏差不大,却实实在在削弱了熵,而且完全可以避免。

解决办法是拒绝采样:落在最后那个不完整区间里的字节直接丢弃,重新取一个。本工具正是这么做的,因此所选字母表中的每个字符出现概率完全相等。

长度怎么选

熵值等于 log2(字母表大小) × 长度 比特。62 字符的字母表每个字符约 5.95 比特,因此 22 位令牌约携带 131 比特,暴力破解已无从下手。凡是用于保护真实访问权限的场景,128 比特是通行下限;低于约 64 比特时,攻击者只要有一个响应够快的接口,威胁就变得真实。

字母表的选择主要取决于令牌要经过哪些环节。Base64url 和十六进制可以原样穿过 URL、文件名和 HTTP 头。无歧义字母表剔除了 0/O、1/l/I 这类易混字符,凡是需要人念出来或照着屏幕重新输入的场景都值得使用。

开源说明:使用浏览器原生的 crypto.getRandomValues API 实现,不依赖任何第三方库。

常见问题

令牌是在我的设备上生成的吗?
是的,完全在浏览器内通过 crypto.getRandomValues() 生成。不会发送到任何服务器,也不会记录日志,你看到的值只有你自己知道。
令牌应该多长?
凡是用于保护访问权限的场景,至少要有 128 比特熵:62 字符字母表下取 22 位,或 32 位十六进制。仅作非安全标识用途时可以更短。
为什么不能用 Math.random()?
它是速度优先的伪随机生成器,种子往往来自时钟这类廉价来源。攻击者只要观察到少量输出,通常就足以还原内部状态并预测今后的每一个值。
「无歧义字符」选项有什么用?
它会剔除 0/O 与 1/l/I,让令牌在被念出来、抄在纸上或照着屏幕重新输入时不会因为字形混淆而出错。
可以用它生成密码重置链接吗?
可以,但你需要只存储令牌的哈希、设置较短的有效期,并在使用一次后立即作废。随机性这里已经足够,生命周期管理是你的应用要负责的部分。
同一个令牌会不会再次出现?
在 128 比特熵下重复的概率低到可以忽略,但本工具不保存任何历史记录,因此无法替你验证多次生成之间的唯一性。