PHP password_verify()和slow等于比较


PHP password_verify() and slow equals comparison

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

现在,简单的例子:

$hash = '$2y$10$HH3906lfby7HOy1N3duQh.Kju.84ct6AcMZm2p/SYZsZSXuYWvvT.';
$startTime = microtime(TRUE);
password_verify('rasmuslerdorf', $hash);
$endTime = microtime(TRUE);
$time = $endTime - $startTime;

这总是会产生略有不同的输出,根据这篇文章("为什么这个页面上的哈希代码会比较"长度常数"时间中的哈希?"段落),这些输出可能被用于定时攻击以获取哈希。我认为这些结果看起来有点随机,但肯定不是恒定的。

问题是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

简短回答:是的,确实如此。

长话短说:没有必要。

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

$2y$10$9JxHB8U1QKsLS/ynplKzm.iIO7f6gtTKYA61ppVuANYxWNCA5DW1S
$2y$10$ILlWQrYyDJvHHkxcCgjm7OThLRAmMcTzsJOZOwjaSYiRUHq8LVYde
$2y$10$8JfydDKUNbOeiybwZ9m.j.5TC8CBqkc3RZu2DX42A4dFNpNYPWfzm
$2y$10$qeG.53lr9PVVGN4Yk.kSZuOMpfone5kINyWVpAf2gUXPseU2WdSzK
$2y$10$nZUgPUwiXIvCJ9BY1wbtbuV5vH6yff9CNyumFsI/NN2eJmf20iec.

这是同一密码的5个不同散列。格式为:

$2y$10$saltsaltsaltsaltsaltsahashhashhashhashhashhashhashhas

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

stored password "test":
hash = $2y$10$9JxHB8U1QKsLS/ynplKzm.iIO7f6gtTKYA61ppVuANYxWNCA5DW1S

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

$2y$10$9JxHB8U1QKsLS/ynplKzm.FTYpGS/gNDw4SB6YD0wEtCSPgGvtPim

现在,让我们并排来看这两个散列:

$2y$10$9JxHB8U1QKsLS/ynplKzm.iIO7f6gtTKYA61ppVuANYxWNCA5DW1S
$2y$10$9JxHB8U1QKsLS/ynplKzm.FTYpGS/gNDw4SB6YD0wEtCSPgGvtPim

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

如果攻击者能够对攻击进行定时比较,那将没有任何好处。因为他们不知道salt(因此推断散列只是浪费时间,因为没有salt他们就无法确定密码)。

因此,时间安全并不是绝对必要的。

为什么会包括在内?因为每个人都会犯错。因为纵深防守是个好主意。因为该分析假设,如果没有salt,哈希的任何内容都是有用的(例如:如果bcrypt中的一个缺陷基于密码对哈希产生了偏见,那么在不知道salt的情况下,密钥空间将从72^255减少)。

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