用 bcrypt 或 Argon2 对密码进行哈希,或与已存储的哈希比对
这个密码哈希生成器可创建 bcrypt 哈希(<code>$2b$</code>,成本 4 到 15),以及标准 PHC 字符串格式的 Argon2id、Argon2i 和 Argon2d 哈希,内存、迭代次数、并行度、盐长度和输出长度都可自行设置。切换到<strong>验证</strong>后,可粘贴数据库中的哈希,根据前缀识别其算法和参数,并测试密码是否匹配。每个哈希都使用新的随机盐,并显示在你设备上耗费的时间。哈希计算通过浏览器中的 WebAssembly 运行,密码绝不会上传。
如何生成 bcrypt 或 Argon2 哈希
- 1选择哈希,然后选择算法:新系统用 Argon2id,与现有系统保持一致则用 bcrypt。
- 2设置成本:bcrypt 的成本因子,或 Argon2 预设,如 OWASP 19 MiB, t=2。如需匹配某个配置,可手动调整内存、迭代次数和并行度。
- 3输入密码并点击生成哈希。编码后的哈希、各组成部分和耗时会显示在下方。
- 4要检查哈希,请选择验证,粘贴已存储的哈希和密码,然后点击验证。
为什么密码需要慢速哈希
SHA-256 这类快速哈希并不适合密码。一块显卡每秒可计算数十亿次 SHA-256,因此泄露的 SHA-256 密码哈希表可以按这个速度被猜解。密码哈希函数被设计得很慢,Argon2 还需要大量内存,让每次猜测都要付出真实的时间和硬件成本。在你的服务器上耗时四分之一秒的设置,同样会让攻击者对每个用户的每次猜测都付出四分之一秒。
每个哈希还带有自己的随机盐,因此两个密码相同的用户会得到不同的哈希,预先计算的彩虹表毫无用处。盐和所有参数都保存在哈希字符串中,所以库仅凭哈希就能验证密码。
解读 bcrypt 哈希
像 $2b$12$R9h/cIPz0gi.URNNX3kh2OPST9/PgBkqquzi.Ss7KIUgO2t0jWMUW 这样的 bcrypt 哈希由四部分组成:版本 2b、成本 12(212 = 4,096 轮密钥扩展)、22 个字符的盐和 31 个字符的哈希,后两者都使用 bcrypt 自有的 Base64 字母表。成本每增加 1,耗时翻倍。
对于不超过 72 字节的密码,$2a$、$2b$ 和 $2y$ 的计算结果相同;这些字母标记的是对旧实现缺陷的修复。bcrypt 只读取密码的前 72 字节并忽略其余部分,本工具会对此给出提示——较长的口令短语,或使用中文等非拉丁文字(一个字符占 2 到 4 字节)的密码,可能比你预想的更早达到这个上限。
Argon2id、Argon2i 和 Argon2d
PHC 字符串记录了验证所需的全部信息:$argon2id$v=19$m=19456,t=2,p=1$<salt>$<hash> 表示版本 1.3、19,456 KiB 内存、2 次迭代和 1 条通道,后面是无填充 Base64 编码的盐和哈希。
- Argon2id
- 下面两种变体的混合版本,也是 RFC 9106 和 OWASP 推荐用于密码存储的变体。除非有特殊限制,否则就用它。
- Argon2i
- 内存访问与密码无关,可抵御侧信道攻击,但在迭代次数较少时对 GPU 破解的抵抗力较弱。
- Argon2d
- 内存访问依赖于密码:对 GPU 的抵抗力最强,但易受侧信道攻击。适合工作量证明,不适合用于校验登录的服务器。
推荐设置
- Argon2id:OWASP 推荐 19 MiB 内存、2 次迭代、并行度 1,或等效的折中方案,如 47 MiB 配 1 次迭代,或 12 MiB 配 3 次迭代。RFC 9106 建议在内存允许时使用 64 MiB、3 次迭代和 4 条通道。
- bcrypt:成本至少为 10;如今 12 是常见默认值。选择你的登录接口能承受的最高成本——服务器上每个哈希约 250 毫秒是合理目标。
- 盐:16 个随机字节。哈希长度:32 字节已绰绰有余。
- 这里测得的时间是在你的设备上通过 WebAssembly 运行的结果,通常比服务器上的原生库慢。确定成本前,请在生产硬件上进行基准测试。
何时使用本工具
可用它为种子用户或配置文件生成哈希,确认数据库中的哈希是否真的与你认为的密码匹配,或查明某个现有哈希使用了哪些参数。你的应用应在用户注册时用自身的库对密码进行哈希,绝不应把明文密码发送到网站上去哈希。如需先生成一个强密码,请使用密码生成器;如需带密钥的签名而非密码存储,请参阅 HMAC 生成器。
常见问题
- 应该用 bcrypt 还是 Argon2?
- 新系统用 Argon2id:它是 Password Hashing Competition 的优胜者,且是内存困难型算法,使 GPU 和 ASIC 破解的成本大幅提高。bcrypt 仍可接受且支持非常广泛,如果你的技术栈已在使用,可以继续保留。
- 为什么同一个密码每次生成的哈希都不同?
- 每个哈希都使用新的随机盐,所以每次输出都会变化。这是有意为之。要检查密码,请将其与已存储的哈希进行验证,而不是比较两个新生成的哈希。
- bcrypt 或 Argon2 哈希可以解密吗?
- 不能。它们是单向函数。找出密码的唯一方法是猜测候选密码并逐一哈希,而这些算法刻意让这一过程变慢。
- bcrypt 的 72 字节限制是什么?
- bcrypt 只使用密码的前 72 字节。之后的内容不会影响哈希,因此前 72 字节相同的两个长密码会得到匹配的哈希。Argon2 没有这种限制。
- bcrypt 应该用多大的成本因子?
- 至少 10,12 是常见默认值。每加 1,计算量翻倍。选择能让服务器上的登录速度仍可接受的最高值。
- $2a$、$2b$ 和 $2y$ 的 bcrypt 哈希兼容吗?
- 兼容。对于不超过 72 字节的密码,它们生成相同的哈希。大多数库接受这三种前缀,本工具也都能验证。
- 为什么验证和生成哈希耗时一样长?
- 验证就是用哈希中保存的盐和参数对密码重新哈希并比较结果,因此计算量完全相同。正是这一点让猜测变得代价高昂。
- 密码会发送到服务器吗?
- 不会。bcrypt 和 Argon2 在你浏览器中的 WebAssembly 里运行。你输入的任何内容都不会离开页面。