web-dev-qa-db-ja.com

PHPとNodeJSの間のBCryptハッシュの比較

私が取り組んでいるアプリの場合、nodejsはPHPによって作成されたハッシュを検証する必要があり、その逆も同様です。

問題は、PHPで生成されたハッシュ(PHPのpassword_hash関数を使用するLaravelの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 failed nodejs pass'、一方、次の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でテストを実行しました。

31
wolfemm

Phpとnodeから生成されるbcryptハッシュのタイプが異なるため、これは失敗します。 Laravelは$2y$を生成しますが、ノードは$2a$を生成します。ただし、2a2yの違いは接頭辞のみです。

したがって、できることは、プレフィックスの1つを他のプレフィックスと同様にすることです。お気に入り:

$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);

Node

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

次に、phpGeneratedHashfinalNodeGeneratedHashを比較します。

注:PHPで比較する場合は、NodeJSで生成されたハッシュのプレフィックスを$2y$に変更し、NodeJSで比較する場合はそれをお勧めします。 PHP生成されたハッシュのプレフィックスを$2a$に変更します。

55
majidarif

私は前に言われたことを計算して、機能するコードを取得しようとしました。ご覧のとおり、何も交換する必要はありません。

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

異なる言語での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のハッシュされた文字列をGoで比較するとエラーが発生する場合があります。

0
S.K.