Bcrypt 加密与校验

在浏览器里生成和校验 bcrypt 哈希:可选 $2b$、$2y$、$2a$ 前缀与 4–31 的成本,提示 72 字节上限,并说明 PHP、Laravel、Node.js、Go、Spring 能否识别。密码不上传。

  • 在浏览器中处理
  • 数据不离开你的设备
  • 免费 · 无需注册
按实际校验哈希的程序选择前缀。PHP 和 Laravel 用 $2y$,Node.js bcrypt 用 $2b$。下方说明列出所选前缀的兼容情况。
成本可选 4–31,默认为 12。每增加 1,计算量翻倍。耗时按本浏览器的实测速度估算,登录服务器仍需实测。
点“生成哈希”才开始计算,每次生成随机的 16 字节盐。结果分为前缀、成本、22 字符盐和 31 字符哈希。“取消”会停止当前计算。

计数按 UTF-8 字节计算。bcrypt 只读取前 72 字节;空格和换行也计入,且不做 Unicode 规范化。超过上限会显示警告。

哈希在本标签页的 Web Worker 中计算。密码和哈希不会发送到任何地方,也不会保存;本页不加载统计和广告。

示例、说明与常见问题 带实际输出的示例、与同类工具的差别,以及常见问题。

实例:重置若依(RuoYi)的管理员密码

若依前后端分离版(RuoYi-Vue)用 Spring Security 的 BCryptPasswordEncoder 加密密码(SecurityUtils.encryptPassword)。初始化脚本 sql/ry_20260417.sql 里,admin 和 ry 两个账号的 password 字段都是下面这个值,README 写明演示账号是 admin / admin123。把它粘贴到「校验」页,输入 admin123,结果是「匹配」:

$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2

上线前要换掉这个默认密码时,在「生成」页输入新密码,前缀选 $2a$、成本选 10(和若依自己生成的一致),把结果写回数据库:

UPDATE sys_user SET password = '把生成的哈希粘贴在这里' WHERE user_name = 'admin';

改完再用「校验」页核对一次新密码和哈希,确认没有复制漏字符。

实例:粘贴来的值不是标准格式

从不同地方复制出来的哈希常常带着「外壳」。Spring Security 的 DelegatingPasswordEncoder 会在前面加 {bcrypt};Spring Security 7.1.1 用 PasswordEncoderFactories.createDelegatingPasswordEncoder() 生成的一个值如下(密码 Ruoyi@2026),本页会去掉 {bcrypt} 再校验:

{bcrypt}$2a$10$Syj8x8XixpYEkWocxvjgbuqT3xOMxpG.utD30HGZwQBzRMIxVnroC

同样会处理的还有:前后的引号和空格、htpasswd 行开头的 用户名:、Docker Compose 里写成 $$ 的美元符号、Django 的 bcrypt$ 与 bcrypt_sha256$(后者先对密码做 SHA-256)。哈希本身坏了时会指出位置,例如少了最后一个字符会提示「应有 60 个字符,这里只有 59 个」:

$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu

选哪个前缀

对 UTF-8 密码来说,$2a$、$2b$、$2y$ 的算法相同:$2y$ 标记修复 CVE-2011-2483 之后的 crypt_blowfish 结果,$2b$ 是 OpenBSD 2014 年改用的标记,crypt_blowfish 1.3 对 $2b$ 的处理与 $2y$「完全相同」(Openwall)。真正的差别在于各个库认不认。2026-10-02 我们用同一批哈希逐个测试:

库版本$2a$$2b$$2y$超过 72 字节时生成默认写出
PHP password_verify 8.4.26✓✓✓✂ 截断$2y$12$
Laravel Hash::check 13.34.0⚠ 抛异常⚠ 抛异常✓✂ 截断$2y$12$
Python bcrypt 5.0.0✓✓✓✗ 报错$2b$12$
Python bcrypt 4.2.0✓✓✓✂ 截断$2b$12$
Node.js bcrypt 6.0.0✓✓✗ false✂ 截断$2b$10$
Node.js bcryptjs 3.0.3✓✓✓✂ 截断$2b$10$
Go x/crypto/bcrypt 0.57.0✓✓✓✗ 报错$2a$10$
Spring Security 7.1.1✓✓✓✗ 报错$2a$10$
Spring Security 6.5.11✓✓✓✗ 报错$2a$10$
Symfony 8.1.0✓✓✓先做 SHA-512$2y$13$

Laravel 的框架配置默认 HASH_VERIFY 为 true,PHP 的 password_get_info() 只把 $2y$ 认作 bcrypt,所以 $2a$、$2b$ 会抛 This password does not use the Bcrypt algorithm.。结论:给 PHP / Laravel 用 $2y$,给 Node.js 用 $2b$,Java、Go、Python 三种都行。只改前缀,哈希依然有效,「校验」页会直接列出另外两种写法。

72 字节与中文密码

bcrypt 最多读密码的前 72 个字节。UTF-8 里一个汉字通常占 3 个字节,所以 24 个汉字就到上限:

我家的猫叫小橘子它今年三岁了最喜欢在阳台上晒太阳

这句正好 72 字节,再多一个字就不起作用。超过上限时各库的做法不同:PHP、Node.js bcrypt、bcryptjs 悄悄截断;Python bcrypt 5、Go、Spring Security 6.3 及以上直接报错(我们测到 6.2.8 仍截断)。本页会提示最后一个被计入的字,并在校验结果里注明「只比较了前 72 字节」。

成本怎么选

成本是 2 的指数:成本 12 做 212 = 4,096 轮密钥设置,比成本 11 慢一倍。OWASP 密码存储速查表要求至少 10,并把 bcrypt 定为「只在没有 Argon2 和 scrypt 的旧系统里使用」;新项目优先 Argon2id。本页显示的耗时是浏览器里 JavaScript 实现的速度,服务器上的原生库通常更快,最终以登录服务器上的实测为准。

与其他在线工具的区别

2026-10-02 用同一组输入测试了 cn.bing.com 搜「bcrypt 在线」排在前面的 xyutil.com 和 33tool.com:两者都在浏览器里计算,只生成 $2a$;73 字节的密码对比前 72 字节的哈希,两者都显示匹配且不提示;含 ! 的哈希两者都只说「不匹配」,不指出格式错误。本页可选前缀,并说明不匹配的具体原因。

限制

  • 计算用 bcryptjs 2.4.3。成本最高可选 31,但在浏览器里要算几天,可随时点「取消」。
  • $2x$(旧 crypt_blowfish 缺陷产生的哈希)只在密码全是 ASCII 时按 $2a$ 校验。
  • 密码按输入的字符原样转成 UTF-8,不做 Unicode 规范化。
  • 只支持 bcrypt,Argon2、scrypt、SHA-crypt 等会被识别出名称但不校验。生成 Apache / Nginx 用的文件请用 htpasswd 生成器,生成随机密码请用密码生成器。

FAQ

bcrypt 能解密吗?

不能。bcrypt 是单向哈希,没有密钥,也没有反向运算。所谓校验,是用同一个盐和成本把你输入的密码再算一遍,看结果是否相同。忘了原密码只能重置:生成新哈希写回数据库。

Spring Boot 项目该选哪个前缀?

Spring Security 的 BCryptPasswordEncoder 默认写 $2a$,读取时 $2a$、$2b$、$2y$ 都认(6.5.11 与 7.1.1 实测),所以选哪个都能登录。要和 Spring 自己生成的值保持一致,就选 $2a$。

同一个密码每次生成的哈希都不一样,正常吗?

正常。每次都会随机生成 16 字节的盐,盐写在哈希的第 8–29 个字符里。校验时从哈希里取出盐再计算,所以任何一个结果都能通过校验。

成本选多少合适?

OWASP 要求至少 10。PHP 8.4、Laravel、Python 默认 12,Node.js bcrypt、Go、Spring Security 默认 10。在实际负责登录的服务器上计时,选能在远低于 1 秒内算完的最高值。

密码会被上传吗?

不会。计算在当前标签页的 Web Worker 里进行,页面不发送密码或哈希,也不保存;本页不加载统计和广告。