在Node.js中验证由PHP生成的密码哈希

32

我的 PHP 代码使用 password_hash 生成哈希值并将其存储在数据库中。以下是 PHP 代码:

$hash = password_hash($value, PASSWORD_BCRYPT, array('cost' => $cost));

我想在nodejs中校验/检查密码是否与此哈希值匹配。

我看过很多Node模块(bcrypt、phpass、node-bcrypt),但它们都给了我假的结果。以下是在PHP中生成的示例哈希值,我正在尝试在nodejs中验证它。

var hash = '$2y$08$9TTThrthZhTOcoHELRjuN.3mJd2iKYIeNlV/CYJUWWRnDfRRw6fD2';

var bcrypt = require('bcrypt');

bcrypt.compare("secret", hash, function(err, res) {
    console.log(res);
});

(这里的“secret”是真正的密码)

我目前的解决办法是通过node调用一个php脚本来验证(对于任何需要解决办法的人)

var exec = require('child_process').exec;
var cmd = 'php verify.php password encryped_pasword';
exec(cmd, function (error, stdout, stderr) {
  // output is in stdout
  console.log(stdout);
 //If stdout has 1 it satisfies else false
});

这是一种hack,而不是解决这个问题的好方法。有没有一种在nodejs中验证密码而不使用类似于这样的变通方法的方式?


你看过 https://www.npmjs.org/package/bcrypt-nodejs 吗? - rcbevans
@o0rebelious0o 我尝试使用它进行比较,但它返回 null 而不是 false,也没有错误。 - Sudesh
注意,$cost必须匹配getRounds(),这是bcrypt的工作原理。 - erenon
2个回答

67

用$2a$替换哈希密码中的$2y$,这样bcrypt.compare就能给出正确的结果。

var hash = '$2y$08$9TTThrthZhTOcoHELRjuN.3mJd2iKYIeNlV/CYJUWWRnDfRRw6fD2';
var bcrypt = require('bcrypt');
hash = hash.replace(/^\$2y(.+)$/i, '$2a$1');
bcrypt.compare("secret", hash, function(err, res) {
    console.log(res);
});

关于ES6:

import bcrypt from 'bcrypt';
let hash = '$2y$08$9TTThrthZhTOcoHELRjuN.3mJd2iKYIeNlV/CYJUWWRnDfRRw6fD2';
hash = hash.replace(/^\$2y(.+)$/i, '$2a$1');
bcrypt.compare('secret', hash, function(err, res) {
    console.log(res);
});

4
这对我很有帮助,谢谢!不过如果有人知道的话,我会很想知道为什么需要这样做? - iamjonesy
1
评论以获取此内容的更新(如果有的话,因为已经超过一年了!) - Sushruth
1
我希望这是Medium,我可以给它更多应得的点赞。 - Steven Kaspar
谢谢你的回答! - shilpa sree
9
$2a$$2y$只是前缀,表示使用的算法版本。2011年,PHP实现中出现了一个重大错误,因此启动了一个倡议,将原始前缀$2a$更改为$2x$以表明哈希是使用错误的算法完成的,而$2y$表示它是正确的。除了PHP之外,没有其他人采纳这个建议。这就是为什么node.js bcrypt不识别该前缀,而PHP crypt_blowfish可以。 - Eduardo Palacio

32

我知道这个问题已经有答案了,但是从评论中看来需要更多的细节。

php password_hash() 函数生成的 Bcrypt 哈希被分为以下部分:

$2y$ 08$ 9TTThrthZhTOcoHELRjuN. 3mJd2iKYIeNlV/CYJUWWRnDfRRw6fD2

|     |     |                     |
|     |     Salt                  Hashed Password
|     |
|     Algorithm options (cost, in this case)
|
Algorithm type

从Stack Overflow的其他答案看来,虽然PHP和Node版本的Bcrypt使用不同算法,但哈希输出的唯一区别是前缀。所以需要做的就是,如@Sudesh所提到的,将$2y$替换为$2a$,这样就没问题了。

来源

http://php.net/manual/en/faq.passwords.php

$2y bcrypt hashes in Node.js

Comparing BCrypt hash between PHP and NodeJS


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接