PHP password_verify() vs Python bcrypt.hashpw()


PHP password_verify() vs Python bcrypt.hashpw()

好了。

我已经设置了一个[简单]PHP REST API,我通过X-API-KEY头密钥接收散列密码。当与另一个PHP脚本接口并且通过PHP的password_hash()方法对短语进行散列时,这非常有效。但是,当我尝试通过Python和Requests库与API接口时,密钥被拒绝。以下是一些示例:

PHP:

<?php
$usrid = '123456';
$dt     = new DateTime();
$secret = "secret{$usrid}{$dt->format('Ymd')}";
$hashed = password_hash($secret, PASSWORD_BCRYPT);
echo $secret."'n";
echo $hashed."'n";
echo(phpversion());
?>
Python:

#!/usr/bin/python
import bcrypt, datetime, sys
usrid = '123456' # user id
t = datetime.datetime.now().strftime('%Y%m%d')
secret = "secret{usrid}{t}".format(usrid=usrid,t=t)
hashed = bcrypt.hashpw(secret, bcrypt.gensalt())
print secret
print hashed
print '%d.%d.%d' % (sys.version_info[:3])

它们的输出如下所示:

PHP:
    secret12345620161116
    $2y$10$/WUBS2RkTlfcgPxvmqYRI.EkBD/CPgnpE9rYvOqweERgSwFeENUDO
    5.6.24
Python: 
    secret12345620161116
    $2b$11$9v/l6KglHiNgOybw1Y8jWeCFHiAfv.cguO1Qmc7Noe4azSluoBeHO
    2.7.11

现在,它们显然是不同的,这就是重点,但是当您将Python输出传递给PHP password_verify()函数时,它返回False。PHP输出验证无误。

我一定错过了什么,但是我怎么也找不到。我试过用不同的盐,但都没有成功。我错过了什么?这两者就是不相容吗?如果这是真的,那似乎很愚蠢。

先进地感谢你们,你们这些聪明的互联网人。

[我已经用以下两行更新了测试脚本]

PHP: $hashed = password_hash($secret, PASSWORD_BCRYPT, ['cost'=>11]);
Python: hashed = bcrypt.hashpw(secret, bcrypt.gensalt(11))

我已经用这个[PHP]来验证上面的内容:

<?php
$secret = 'secret12345620161116';
$php    = '$2y$11$rMqK7PhWtYd3E6yqqor0K.p2XEOJqbxJSrknLLWfhqZKsbYRa1YRa'; // output from php script
$python = '$2b$11$yWzCNB4dfIIVH2FLWWEQ/efSmN/KlVmLq.MGJ54plgedE1OSQgvPu'; // putput from python script
$php_needs_rehash    = password_needs_rehash($php, PASSWORD_BCRYPT);
$python_needs_rehash = password_needs_rehash($python, PASSWORD_BCRYPT);
echo 'php_needs_rehash: '.$php_needs_rehash."'n";
echo 'python_needs_rehash: '.$python_needs_rehash."'n";
echo "'n";
echo "php_info:'n";
print_r(password_get_info($php));
echo "'n";
echo "python_info:'n";
print_r(password_get_info($python));
echo "'n";
echo "php_verified: ".password_verify($secret, $php)."'n";
echo "python_verified: ".password_verify($secret, $python)."'n";
echo "'n";
?>

输出如下:

php_needs_rehash: 1
python_needs_rehash: 1
php_info:
Array
(
    [algo] => 1
    [algoName] => bcrypt
    [options] => Array
        (
            [cost] => 11
        )
)
python_info:
Array
(
    [algo] => 0
    [algoName] => unknown
    [options] => Array
        (
        )
)
php_verified: 1
python_verified: 1

所以,现在我真的很困惑,因为服务器仍然不识别我的python散列键,如果我不像richardhsu在评论中建议的那样将"$2b"替换为"$2y",即

从技术上讲,它们都是bcrypt或crypt-blowfish的不同版本

在PHP中的前缀是$2y$10$在python中,前缀是$2b$11$

这意味着成本因素略有不同,分别为10比11在你的更新中,你已经将成本因素都固定为11

前缀的另一部分表明php正在使用CRYPT_BLOWFISH哈希,而python正在使用基于Blowfish密码的bcrypt。

由于这些差异,这两个密码不能互换

我找到了passlib并且工作完美

你需要安装

pip install passlib
pip install bcrypt

示例代码

from passlib.hash import bcrypt
php_hashed='$2y$10$/WUBS2RkTlfcgPxvmqYRI.EkBD/CPgnpE9rYvOqweERgSwFeENUDO'
plain_secret='secret12345620161116'
bcrypt.verify(plain_secret,php_hashed)
#output True