比较PHP和NodeJS之间的BCrypt哈希

时间:2014-10-30 01:32:23

标签: php node.js bcrypt

对于我正在处理的应用程序,nodejs需要验证PHP创建的哈希值,反之亦然。

问题是,PHP中生成的哈希(通过Laravel的Hash类,只使用PHP的password_hash函数)在node.js中测试时返回false。

以下node.js脚本:

var bcrypt = require('bcrypt');

var password = 'password';

var phpGeneratedHash  = '$2y$10$jOTwkwLVn6OeA/843CyIHu67ib4RixMa/N/pTJVhOjTddvrG8ge5.';
var nodeGeneratedHash = '$2a$10$ZiBH5JtTDtXqDajO6f4EbeBIXGwtcGg2MGwr90xTH9ki34SV6rZhO';

console.log(
  bcrypt.compareSync(password, phpGeneratedHash)  ? 'PHP passed' : 'PHP failed',
  bcrypt.compareSync(password, nodeGeneratedHash) ? 'nodejs passed' : 'nodejs failed'
);

输出:'PHP失败的nodejs已通过',而以下PHP脚本:

<?php

$password = 'password';

$phpGeneratedHash  = '$2y$10$jOTwkwLVn6OeA/843CyIHu67ib4RixMa/N/pTJVhOjTddvrG8ge5.';
$nodeGeneratedHash = '$2a$10$ZiBH5JtTDtXqDajO6f4EbeBIXGwtcGg2MGwr90xTH9ki34SV6rZhO';

print password_verify($password, $phpGeneratedHash)  ? 'PHP passed' : 'PHP failed';
print password_verify($password, $nodeGeneratedHash) ? 'nodejs passed' : 'nodejs failed';

输出'PHP传递的nodejs传递'。

我使用PHP 5.5.18,node.js v0.10.32和npm bcrypt模块在Ubuntu 14.04.1中运行测试。

3 个答案:

答案 0 :(得分:54)

这是失败的,因为从php和节点生成的bcrypt哈希的类型是不同的。 Laravel生成$2y$,而节点生成$2a$。但好消息是2a2y之间的唯一区别是它们的前缀。

所以你可以做的是使其中一个前缀类似于另一个。像:

$phpGeneratedHash  = '$2y$10$jOTwkwLVn6OeA/843CyIHu67ib4RixMa/N/pTJVhOjTddvrG8ge5.';
$nodeGeneratedHash = '$2a$10$ZiBH5JtTDtXqDajO6f4EbeBIXGwtcGg2MGwr90xTH9ki34SV6rZhO';

类似于:

$phpGeneratedHash  = '$2y$10$jOTwkwLVn6OeA/843CyIHu67ib4RixMa/N/pTJVhOjTddvrG8ge5.';
$nodeGeneratedHash = '$2y$10$ZiBH5JtTDtXqDajO6f4EbeBIXGwtcGg2MGwr90xTH9ki34SV6rZhO';

请注意,我已将节点哈希的$2a$替换为$2y$。您只需执行以下操作:

PHP

$finalNodeGeneratedHash = str_replace("$2a$", "$2y$", $nodeGeneratedHash);

节点

finalNodeGeneratedHash = nodeGeneratedHash.replace('$2a$', '$2y$');

然后将phpGeneratedHashfinalNodeGeneratedHash进行比较。

  

注意:如果您在PHP中进行比较,建议您将NodeJS生成的哈希的前缀更改为$2y$,如果您在NodeJS中进行比较,则;将PHP生成的哈希的前缀更改为$2a$

答案 1 :(得分:2)

我试图计算之前所说的内容,以获得有效的代码。如你所见,我不需要更换任何东西。

在PHP 7.2.4方面:

<?php
$password = "test123";
    $hash = password_hash($password, PASSWORD_BCRYPT);
    echo $hash; // I get $2y$10$5EaF4lMSCFWe7YqqxyBnR.QmDu1XhoiaQxrOFw.AJZkGCYmpsWDU6

在nodeJS方面:

安装bcryptjs包:npm i bcryptjs

var bcrypt = require('bcryptjs');
let hash1="$2y$10$5EaF4lMSCFWe7YqqxyBnR.QmDu1XhoiaQxrOFw.AJZkGCYmpsWDU6";
console.log(bcrypt.compareSync("test123", hash1)); // display true

答案 2 :(得分:0)

使用不同语言的bcrypt的实现可能有所不同。

例如,在Node.js版本bcrypt.js中,应用的盐长度为29个字符

    bcrypt.getSalt = function(hash) {
        if (typeof hash !== 'string')
            throw Error("Illegal arguments: "+(typeof hash));
        if (hash.length !== 60)
            throw Error("Illegal hash length: "+hash.length+" != 60");
        return hash.substring(0, 29);
    };

但是,在Go版本golang.org/x/crypto/bcrypt中,盐大小为22个字节:

const (
    majorVersion       = '2'
    minorVersion       = 'a'
    maxSaltSize        = 16
    maxCryptedHashSize = 23
    encodedSaltSize    = 22
    encodedHashSize    = 31
    minHashSize        = 59
)

因此,在Go语言中与其他语言进行比较时,Node.js中的哈希字符串可能会出错。