PHP密码产生不同的结果


PHP crypt producing different results

好吧,我在这里坐了好几个小时,一直在为这个问题挠头,我不知道出了什么问题。我试图通过带有crypt的随机salt加密密码,但当我尝试登录时,总是错误的。

让我带你浏览一下脚本:

$cost = 10;
$salt = strtr(base64_encode(mcrypt_create_iv(16, MCRYPT_DEV_URANDOM)), '+', '.');
$salt = sprintf("$2y$%02d$", $cost) . $salt;
$hash = crypt($password, $salt);
echo $hash;
echo crypt($password, $hash);

以"asdfgh"的密码输出以下内容:

$2y$10$865uru.sXJheD9TQKLDnZuTZfpAXv83UDuaSFfb.G2qIxBzEb1pOi
$2y$10$865uru.sXJheD9TQKLDnZuTZfpAXv83UDuaSFfb.G2qIxBzEb1pOi

数据库中的散列如下:

$2y$10$865uru.sXJheD9TQKLDnZuTZfpAXv83UDuaSFfb.G2qIxBzEb1pOi

对于登录脚本,我们有以下代码用于测试:

echo $data->hash . '<br>';
echo crypt('asdfgh', $data->hash) . '<br>';
echo crypt('asdfgh', '$2y$10$865uru.sXJheD9TQKLDnZuTZfpAXv83UDuaSFfb.G2qIxBzEb1pOi');

它输出以下内容:

$2y$10$865uru.sXJheD9TQKLDnZuTZfpAXv83UDuaSFfb.G2qIxBzEb1pOi
$2y$10$865uru.sXJheD9TQKLDnZuRRPJQwjWh2PGgtntpcsnRaGzvv5Sfte
$2y$10$865uru.sXJheD9TQKLDnZuRRPJQwjWh2PGgtntpcsnRaGzvv5Sfte

虽然数据库字符串仍然是正确的,即使手动将正确的字符串传递给函数,生成的哈希也会有所不同。我没有解决方案。。。

如果有人能帮助我,我将非常感激。

Windows 上的PHP 5.4.16版本

更新:以下是带盐的更新片段:

$cost = 10;
$salt = strtr(base64_encode(mcrypt_create_iv(16, MCRYPT_DEV_URANDOM)), '+', '.');
$salt = sprintf("$2y$%02d$", $cost) . $salt;
$hash = crypt($password, $salt);
$data = array(
    'id' => '',
    'username' => $username,
    'hash' => $hash,
    'email' => $email,
    'salt' => $salt,
);
$this->mdl_registration->_insert($data);
$this->load->view('registration_submit');

对于登录脚本:

function check_login($password) {
    $username = $this->input->post('username');
    $result = $this->get_where_custom('username', $username);
    foreach($result->result() as $data) {
        echo $data->hash . '<br>';
        echo crypt('asdfgh', $data->salt) . '<br>';
        $test = crypt($password, $data->salt);
        if($test == $data->hash) {
            return TRUE;
        }
        else {
            $this->form_validation->set_message('check_login', 'Invalid Username and / or Password');
            return FALSE;
        }
    }
}

用于测试目的的回波返回以下内容:

$2y$10$ZgbOXM18lArDu/u/Ftsdr.t7VPnLsqLJdC2Dum8pl/flW8LmnnUoS
$2y$10$ZgbOXM18lArDu/u/Ftsdr.s5N5juHB/zq/5SN/7oFAjn9CZKjI9H6

好吧,我的答案实际上并不能解决为什么这段代码不起作用。我认为这是由于$salt没有通过,但显然crypt()说明了这一点,只要salt在提供的$hash内。。。

无论如何,我可以提出一种替代方法来实现这一点。可以忽略这一点,等待解决方案,或者对此进行调整。由你决定。

$password = 'asdfgh';
$salt = dechex(mt_rand(0, 2147483647)) . dechex(mt_rand(0, 2147483647));
$hash = hash('sha256', $password . $salt);
for($round = 0; $round < 60000; $round++)
{
    $hash = hash('sha256', $hash . $salt);
}

这创建了稍微不同的salt,使用了不同的哈希算法,还迭代了60000次哈希(对于用户来说,相对较短的时间为1-2秒)。

将此$salt与$hash一起存储在数据库中。

现在,对于登录脚本,只需包含以下片段。。。

(假设$password为"asdfgh")

$newHash = hash('sha256', $password . $salt);
for($round = 0; $round < 60000; $round++)
{
    $newHash = hash('sha256', $newHash . $salt);
}
if($newHash===$data->hash){
  //Match!
}

我用几个不同的数据集尝试了这个,哈希总是匹配的,所以你可以使用它。

或者你可以等待一位真正的安全专家来解释为什么你的代码不起作用:)

希望这能有所帮助!

您的salt格式错误。

根据文件:

CRYPT_BLOWFISH-用盐进行BLOWFISH哈希,如下所示:"$2a$"、"$2x$"或"$2y$",两位数的成本参数"$",以及字母表"./0-9A-Za-z"中的22个字符。

您的salt有a)无效字符(=作为base64末尾的填充字符)和b)太长(24个字符而不是22个字符)。

这可能是您出现问题的原因。