我有一个问题,无法理解两种不同的字符串比较方式。给定的是以下函数,它比较两个字符串。此功能在Symfony-Framework安全组件中用于比较用户登录过程中的密码。
/**
* Compares two strings.
*
* This method implements a constant-time algorithm to compare strings.
*
* @param string $knownString The string of known length to compare against
* @param string $userInput The string that the user can control
*
* @return Boolean true if the two strings are the same, false otherwise
*/
function equals($knownString, $userInput)
{
// Prevent issues if string length is 0
$knownString .= chr(0);
$userInput .= chr(0);
$knownLen = strlen($knownString);
$userLen = strlen($userInput);
$result = $knownLen - $userLen;
// Note that we ALWAYS iterate over the user-supplied length
// This is to prevent leaking length information
for ($i = 0; $i < $userLen; $i++) {
// Using % here is a trick to prevent notices
// It's safe, since if the lengths are different
// $result is already non-0
$result |= (ord($knownString[$i % $knownLen]) ^ ord($userInput[$i]));
}
// They are only identical strings if $result is exactly 0...
return 0 === $result;
}
来源:来源代码段
我很难理解equals()
函数和简单比较===
之间的区别。我写了一个简单的工作示例来解释我的问题。
给定字符串:
$password1 = 'Uif4yQZUqmCWRbWFQtdizZ9/qwPDyVHSLiR19gc6oO7QjAK6PlT/rrylpJDkZaEUOSI5c85xNEVA6JnuBrhWJw==';
$password2 = 'Uif4yQZUqmCWRbWFQtdizZ9/qwPDyVHSLiR19gc6oO7QjAK6PlT/rrylpJDkZaEUOSI5c85xNEVA6JnuBrhWJw==';
$password3 = 'iV3pT5/JpPhIXKmzTe3EOxSfZSukpYK0UC55aKUQgVaCgPXYN2SQ5FMUK/hxuj6qZoyhihz2p+M2M65Oblg1jg==';
示例 1(按预期操作)
echo $password1 === $password2 ? 'True' : 'False'; // Output: True
echo equals($password1, $password2) ? 'True' : 'False'; // Output: True
示例 2(按预期执行)
echo $password1 === $password3 ? 'True' : 'False'; // Output: False
echo equals($password1, $password3) ? 'True' : 'False'; // Output: False
我读过关于卡普·拉宾算法的信息,但我不确定equals()
函数是否代表卡普·拉宾算法,总的来说我不明白维基百科的文章。
另一方面,我读到equals()
功能将防止暴力攻击,对吗?有人可以解释一下equals()
的优势是什么吗?或者有人可以给我一个例子,===
会失败并且equals()
做正确的工作,这样我就可以理解优势吗?
恒定时间算法是什么意思?我认为恒定时间与实时无关,或者如果我错了?
这个函数只是一个普通的字符串比较函数。这不是拉宾·卡普。它不是恒定时间,它是线性时间,无论评论说什么。它也不能防止暴力攻击。
工作原理:
- 如果正确的密码和用户提供的密码长度不同,则设为 $result != 0
- 遍历用户提供的密码,用正确密码的相应字符对其每个字符进行 xor (如果正确的密码较短,请继续绕圈浏览它),并按位或每个结果$result。
由于仅使用按位 OR,如果任何字符不同,则$result为 != 0。需要步骤 1,否则,如果真实密码是"abc",则会接受用户输入"abca"。
为什么有时会使用这样的字符串比较函数
假设我们以通常的方式比较字符串,正确的密码是"bac"。我们还假设我可以精确测量完成密码检查所需的时间。
我(用户)尝试a
,b
,c
...他们不起作用。
然后,我尝试aa
.该算法比较前 2 个字母 - b
与 a
,看到它是错误的,并返回 false。
我现在尝试使用bb
.该算法比较b
与b
,它们匹配,因此它继续字母#2,比较a
与b
,看到它是错误的,返回false。现在,由于我能够精确地计时算法的执行,我知道密码以"b"开头,因为第二次传递比第一次花费更多的时间 - 我知道第一个字母匹配。
所以我尝试ba
,bb
,bc
...他们失败了。
现在我检查baa
,bbb
,看到baa
运行速度较慢,因此第二个字母a
。这样,我可以逐个字母地确定密码,而不是暴力破解所需的 O(c^N) 次尝试。
这通常并不像这个解释听起来那么令人担忧,因为攻击者不太可能将字符串比较的时间定为如此准确。但有时可以。