背景

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

测试

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

PHP 版,结果正确:

  1. $pwd = 'verygood';
  2. $hash = '$2y$10$2H4dc/JFic6SZF7icQfpmuogmxXDjSq4OOfjr8rxWr81pfq7rnlV2';
  3. if (password_verify($pwd, $hash)) {
  4. echo '密码正确';
  5. } else {
  6. echo '密码错误';
  7. }

node 版,结果错误:

  1. // 引入bcrypt模块
  2. var bcrypt = require('bcrypt');
  3. const pwd = 'verygood';
  4. const hash = '$2y$10$2H4dc/JFic6SZF7icQfpmuogmxXDjSq4OOfjr8rxWr81pfq7rnlV2';
  5. const compare = bcrypt.compareSync(pwd, hash);
  6. if (compare) {
  7. console.log('密码正确')
  8. } else {
  9. console.log('密码错误')
  10. }

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

  1. $pwd = 'verygood';
  2. $hash = password_hash($pwd, PASSWORD_BCRYPT, ['cost' => 10]);
  3. echo $hash;
  4. // 结果
  5. // $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 加密:

  1. // 引入bcrypt模块
  2. var bcrypt = require('bcrypt');
  3. const pwd = 'verygood';
  4. const hash = bcrypt.hashSync(pwd, bcrypt.genSaltSync());
  5. // 结果
  6. // 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 和 node 中使用 bcrypt 加密的不同 - 图1

好吧,统一把 PHP 生成的 hash 前缀从$2y$改成$2b$,登录成功 ~

问题解决 PHP 和 node 中使用 bcrypt 加密的不同 - 图2