hash_equals这个比对的原理是啥?
2025-07-15
hash_equals()
是 PHP 提供的一个函数,专用于比较两个字符串(通常是哈希值)是否相等,其核心目的在于防止时序攻击(Timing Attack)。
✅ 总结原理一句话:
hash_equals()
会逐字节地对比两个字符串的每一个字符,不受第一个不同字符位置的影响,始终耗时一致,以防止通过耗时差异推测密钥或哈希值。
☁️ 为什么要用它,而不是 ===
?
在普通的比较中,如:
if ($a === $b) { ... }
PHP(以及大多数语言)会在第一个字符不同的位置立即返回 false。攻击者可利用这一点——通过精确测量返回所花的时间,逐字节猜测出密钥或 token,称为:
⏳时序攻击(Timing Attack)
⚙️ hash_equals()
的底层对比原理是这样的:
先检查两个字符串长度是否一致:
长度不同,直接返回
false
。若长度相等,则逐字节对比每一位字符:
不管第几位不同,它都会全程跑完整个长度。
用按位或(bitwise OR)把每一对字符的异或(XOR)结果合并起来:
只有当所有字节相等时,最终结果为0。
简单伪代码(简化逻辑)如下:
function hash_equals($a, $b) { if (strlen($a) !== strlen($b)) { return false; } $result = 0; for ($i = 0; $i < strlen($a); $i++) { $result |= (ord($a[$i]) ^ ord($b[$i])); } return $result === 0;}
ord()
取字符的 ASCII 值^
是异或运算:相同为0,不同为1|=
是逐步累积的“或”,只要有不同,就让$result
非0
🧠 举个具体应用场景:
你有一个签名机制:
$expected = hash_hmac('sha256', $data, $secret);$provided = $_GET['signature'];if (hash_equals($expected, $provided)) { // 验证通过}
如果你用 ===
,攻击者可能通过测时不断逼近正确签名;使用 hash_equals()
就能抵抗这类攻击。
🚨 注意事项:
hash_equals()
仅在 PHP 5.6+ 提供。两个参数都必须是字符串,否则会抛出警告。
它只能防止时序攻击,但无法防止其它逻辑漏洞。
🪞延伸阅读推荐:
如夜话,至此。
发表评论: