【问题标题】:PHP crypt producing different resultsPHP crypt产生不同的结果
【发布时间】:2013-08-05 18:32:18
【问题描述】:

好吧,我坐在这里,因为几个小时在这个问题上摸不着头脑,我不知道出了什么问题。我正在尝试通过带有 crypt 的随机盐来加密密码,但是当我尝试登录时,总是错误的。

让我带你看剧本:

$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

更新: 这是更新后的带有盐的 sn-ps:

$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 = strtr(base64_encode(mcrypt_create_iv(16, MCRYPT_DEV_URANDOM)), '+', '.'); $salt = sprintf("$2y$%02d$", $cost) . $salt; 作为盐,第二次使用您的哈希 ($hash) 作为盐
  • 意思是echo crypt('asdfgh', $salt); -> 正如@Elpy 也提到的那样。您应该在用户注册时将$salt 存储在数据库中,然后在登录尝试时检索$salt,将其与密码进行哈希处理并比较哈希值。
  • $data->hash 来自存储在用户表中的数据库。我正在尝试通过 if(crypt($password, $data->hash) == $data->hash) 验证密码,由于结果不同,它总是返回 false。
  • 我也用盐试了一下,结果还是和原来的不一样。
  • echo $hash; & echo crypt($password, $hash); 在第一个 sn-p 中如何输出相同? $password 未设置?

标签: php crypt


【解决方案1】:

好吧,我的回答实际上并没有解决为什么这段代码不起作用。我认为这是由于 $salt 没有通过,但显然 crypt() 说明了这一点,只要盐在提供的 $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);
}

这会稍微不同地创建盐,使用不同的散列算法并且还迭代散列 60,000 次(对于用户来说相对较短 1-2 秒)。

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

现在,登录脚本只需包含这个 sn-p...

(假设 $password 是 'asdfgh')

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

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

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

希望这有帮助!

【讨论】:

  • 遗憾的是它没有:/即使我使用存储在数据库中的盐,我得到的结果完全不同。有趣的是,如果使用散列的反向解密不应该起作用,为什么它在上面的示例中起作用,但在登录脚本中却不起作用?在这一点上我很困惑。
  • 您能否详细说明backward decryption 指的是哪些示例/sn-ps?另外,你能把你用盐尝试的更新结果贴出来吗?就我而言,这很顺利。
  • $hash = crypt($password, $salt);回声$哈希;回声密码($密码,$哈希);两者都有相同的输出:
  • 好点。您实际上是对的,它显然是 crypt 内置的一项功能,以解释它使用的多种散列算法。 Source。更新答案..
  • 我现在用盐测试添加了我的更新。如您所见,结果再次不同。
【解决方案2】:

您的盐格式错误。

根据docs

CRYPT_BLOWFISH - Blowfish 使用盐散列如下:“$2a$”、“$2x$”或“$2y$”、两位数的成本参数“$”和字母表中的 22 个字符“./ 0-9A-Za-z”。

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-01-22
    • 1970-01-01
    • 2018-05-23
    • 2017-09-11
    • 2020-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多