PHP password_verify() 和慢等于比较

PHP password_verify() and slow equals comparison

我一直在寻找有关password_verify()是否使用长度常数时间比较来避免定时攻击的信息。

现在,简单的例子:

$hash = 'y$HH3906lfby7HOy1N3duQh.Kju.84ct6AcMZm2p/SYZsZSXuYWvvT.';

$startTime = microtime(TRUE);
password_verify('rasmuslerdorf', $hash);
$endTime = microtime(TRUE);

$time = $endTime - $startTime;

这总是会产生略有不同的输出,根据 this article"Why does the hashing code on this page compare the hashes in "length-constant" time?" 段落),可以使用在定时攻击中获取哈希。我认为这些结果看起来有点随机,但它们肯定不是恒定的。

问题是password_verify()是否使用长度常数时间比较来避免定时攻击?文档中没有关于它的信息,并且由于我的浅薄经验,我无法很好地解释函数处理时间结果。

答案是肯定的,它使用长度常数时间比较。

这是 php 的 password_verify 函数的摘录

    /* We're using this method instead of == in order to provide
 * resistance towards timing attacks. This is a constant time
 * equality check that will always check every byte of both
 * values. */
for (i = 0; i < hash_len; i++) {
    status |= (ret->val[i] ^ hash[i]);
}

您可以在 https://github.com/php/php-src/blob/master/ext/standard/password.c

查看完整的源代码

简短回答:是的。

长答案:没有必要。

要了解为什么没有必要,我们需要查看正在比较的字符串:

yJxHB8U1QKsLS/ynplKzm.iIO7f6gtTKYA61ppVuANYxWNCA5DW1S
y$ILlWQrYyDJvHHkxcCgjm7OThLRAmMcTzsJOZOwjaSYiRUHq8LVYde
yJfydDKUNbOeiybwZ9m.j.5TC8CBqkc3RZu2DX42A4dFNpNYPWfzm
y$qeG.53lr9PVVGN4Yk.kSZuOMpfone5kINyWVpAf2gUXPseU2WdSzK
y$nZUgPUwiXIvCJ9BY1wbtbuV5vH6yff9CNyumFsI/NN2eJmf20iec.

这是同一密码的 5 个不同哈希值。格式为:

y$saltsaltsaltsaltsaltsahashhashhashhashhashhashhashhas

现在,对于远程攻击者(运行 定时攻击者)来说,盐是秘密。当我们重新散列他们的尝试时,盐是一样的。例如:

stored password "test":
hash = yJxHB8U1QKsLS/ynplKzm.iIO7f6gtTKYA61ppVuANYxWNCA5DW1S

如果攻击者尝试密码 "abc",内部 password_verify() 将调用 crypt("abc", hash)。这将导致:

yJxHB8U1QKsLS/ynplKzm.FTYpGS/gNDw4SB6YD0wEtCSPgGvtPim

现在,让我们并排查看这两个哈希值:

yJxHB8U1QKsLS/ynplKzm.iIO7f6gtTKYA61ppVuANYxWNCA5DW1S
yJxHB8U1QKsLS/ynplKzm.FTYpGS/gNDw4SB6YD0wEtCSPgGvtPim

注意盐是一样的吗?请注意,直到第一个 . 之前的所有内容都是相同的。还要注意攻击者不知道盐是什么。

如果攻击者能够对比较进行定时攻击,那也没什么用。因为他们不知道盐(因此推断散列是什么只是浪费时间,因为没有盐他们无法确定密码)。

所以时间安全并不是绝对必要的。

那为什么会收录呢?因为每个人都会犯错。因为纵深防御是个好主意。因为此分析假设没有盐就没有任何关于散列的有用信息(例如:如果 bcrypt 中的缺陷基于密码使散列有偏差怎么办,所以在不知道盐的情况下密钥空间从 72^255 减少)。

简而言之,拥有它是一件好事,但并不是绝对必要的...