PHP密码哈希检查两个哈希值

4
如果我有两个使用password_hash函数创建的密码哈希值,我怎样判断它们是否来自同一个基本密码?我知道每次都使用不同的盐。我没有原始明文密码。
例如: $2y$10$M6CnjqaxuUKNhg84T8NpLeylkUrvP1pzoZNhBWfpSzP2zJneuS1re$2y$10$ZSlQNIbsLWfj7JLCSkvFLeS/adH.KnGZTgA1BcvyPXl7BEn7GhREO都是由test哈希得到。如果给出这两个哈希值作为参数,如何编写一个返回true的函数?
这种情况可能吗?
所以:
<?php
function check_hashes($hash1, $hash2) {
(some code)
}
echo strval(check_hashes('$2y$10$M6CnjqaxuUKNhg84T8NpLeylkUrvP1pzoZNhBWfpSzP2zJneuS1re', '$2y$10$ZSlQNIbsLWfj7JLCSkvFLeS/adH.KnGZTgA1BcvyPXl7BEn7GhREO'));
echo strval(check_hashes('$2y$10$ZSlQNIbsLWfj7JLCSkvFLeS/adH.KnGZTgA1BcvyPXl7BEn7GhREO', '$2y$10$LoUOu3kt7zm1YZI1PtAsD.yzWF0b9jqOaAH64lK51VtgqRJZBgtO6'));
?>

会输出:

TRUE
FALSE

1
你读过这个吗?http://www.php.net/manual/en/ref.password.php - Digital Chris
2个回答

7

不,除非您已经知道密码,否则无法检查两个哈希值是否属于同一个密码。如果可以,这基本上就失败了使用 password_hash 函数的目的。

如果您知道密码,只需使用方法:password_verify 来验证您的密码:

$res1 = "$2y$10$ZSlQNIbsLWfj7JLCSkvFLeS/adH.KnGZTgA1BcvyPXl7BEn7GhREO";
$res2 = "$2y$10$M6CnjqaxuUKNhg84T8NpLeylkUrvP1pzoZNhBWfpSzP2zJneuS1re";
var_dump(password_verify("test", $res1)); // returns true
var_dump(password_verify("test", $res2)); // returns true

因此,正如您所看到的,两个哈希值都将使用password_verify()方法为您提供true,因此,您无需检查这两个哈希值是否属于相同的密码。如果您仍然要这样做,则可以使用上述逻辑构建类似于以下函数的功能:

function belongs_to_password() {
  $args = func_get_args();
  $str  = array_shift($args);
  foreach ($args as $hash) {
    if (!password_verify($str, $hash)) return false;
  }
  return true;
}

上述函数可用于检查传递给该函数的哈希值是否都属于同一个密码。可以像这样使用:

$res1 = "$2y$10$ZSlQNIbsLWfj7JLCSkvFLeS/adH.KnGZTgA1BcvyPXl7BEn7GhREO";
$res2 = "$2y$10$M6CnjqaxuUKNhg84T8NpLeylkUrvP1pzoZNhBWfpSzP2zJneuS1re";
var_dump(belong_to_password("test", $res1, $res2)); // returns true

1
抱歉,我觉得我没有表达清楚。我的意思是,如果我不知道“test”是基础字符串,仅凭这两个哈希值,是否仍然可以确定它们来自同一个基础字符串? - 735Tesla
2
@735Tesla:是的,我明白了。正如我在回答中所说,你需要知道你的基本字符串。 - Stoic
1
@Stoic 谢谢。既然盐是哈希的前几位的函数,那么有没有比暴力破解这两个更快的方法来找出它们呢? - 735Tesla
2
@735Tesla:除非你知道“基础字符串”,否则我怀疑除了蛮力破解外没有其他办法可以帮到你。我怀疑即使那样也不行! - Stoic

3
关于盐和哈希方法的信息被编码到哈希中。这使得password_verify()可以在不需要独立了解盐的情况下工作(即您无需将盐存储在某个数据库中)。
请注意pasword_verify()文档中的此部分内容:
引用:

请注意,password_hash()返回算法、成本和盐作为返回哈希的一部分。因此,验证哈希所需的所有信息都包含在其中。这允许验证函数在不需要单独存储盐或算法信息的情况下验证哈希。

因此,您只需对两个哈希值运行password_verify()即可。
$hash1_verified = password_verify('test', $hash1);
$hash2_verified = password_verify('test', $hash2);

如果这两个都返回true,它们都是test的哈希值。
为了验证所有哈希值来自同一个基础单词,可以编写一个函数来比较基础单词和任意大小的哈希数组,该函数可能如下所示:
function hash_base_matches_all_hashes($base, $hash_array) {
    for($i = 0; $i < count($hash_array); $i++) {
        if (false === password_verify($base, $hash_array[$i]) {
            return false;
        }
    }
    return true;    
}

1
抱歉我觉得我没有表达清楚。我的意思是,如果我不知道“test”是基础字符串,只给定这两个哈希值,是否仍然可以确定它们来自同一个基础字符串? - 735Tesla
3
不可能在不知道基础字符串的情况下进行测试,这就是单向哈希的目的。 - Mike Brant

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接