bcrypt 加密的坑

背景

原来使用 php 开发的一个项目后端要换成 node,用户密码使用的 bcrypt 加密,数据库保存的加密后的密码,换成 node 后发现总是提醒密码错误。

测试

然后自己写了个测试发现同样的明文密码和加密后的密码,在 PHP 和 node 中校验结果居然不同!!!

PHP 版,结果正确:

$pwd = 'verygood';
$hash = '$2y$10$2H4dc/JFic6SZF7icQfpmuogmxXDjSq4OOfjr8rxWr81pfq7rnlV2';

if (password_verify($pwd, $hash)) {
   echo '密码正确';
} else {
   echo '密码错误';
}

node 版,结果错误:

// 引入bcrypt模块
var bcrypt = require('bcrypt')

const pwd = 'verygood'
const hash = '$2y$10$2H4dc/JFic6SZF7icQfpmuogmxXDjSq4OOfjr8rxWr81pfq7rnlV2'

const compare = bcrypt.compareSync(pwd, hash)

if (compare) {
  console.log('密码正确')
} else {
  console.log('密码错误')
}

然后我分别使用 PHP 和 node 加密同样的密码
PHP 加密:

$pwd = 'verygood';
$hash = password_hash($pwd, PASSWORD_BCRYPT, ['cost' => 10]);
echo $hash;

 // 结果
 // $hash = '$2y$10$fqEsEo0u5PJd5jVdKFJp3OWfHt4o591oH.FDTOB.sDL7/n6FKW8Tm';

PHP 的 password_hash 函数说明看这里~~

PASSWORD_BCRYPT – Use the CRYPT_BLOWFISH algorithm to create the hash. This will produce a standard crypt() compatible hash using the “$2y$” identifier. The result will always be a 60 character string, or FALSE on failure.

根据函数说明我们可知 PASSWORD_BCRYPT 使用的 CRYPT_BLOWFISH 算法,CRYPT_BLOWFISH 算法盐值格式规定是 :

以$2y$开头 + 一个两位cost参数 + $ + 22位随机字符(“./0-9A-Za-z”)

node 加密:

// 引入bcrypt模块
var bcrypt = require('bcrypt')

const pwd = 'verygood'
const hash = bcrypt.hashSync(pwd, bcrypt.genSaltSync())

// 结果
// hash = '$2b$10$6FBNvMILF8RrRMP5BxfPOuNPu8mWEDppksdQjVQd7Qkaf3rzYtlbi';

node 的 bcrypt 说明看这里~~~

This library supports $2a$ and $2b$ prefix bcrypt hashes. $2x$ and $2y$ hashes are specific to bcrypt implementation developed for Jon the Ripper. In theory, they should be compatible with $2b$ prefix.
Compatibility with hashes generated by other languages is not 100% guaranteed due to difference in character encodings. However, it should not be an issue for most cases.

node 的 bcrypt 以$2a$$2b$开头,理论上,与$2y$前缀兼容。 but 由于字符编码不同,与其他语言生成的哈希的兼容性不是 100%保证

好吧,然后我把原来使用 PHP 生成的 hash 前缀从$2y$改成$2b$,
登录成功

问题解决

目录