防止哈希字符串比较的时间攻击的一种方法是执行额外的HMAC签名,以使验证过程随机化(参见https://www.nccgroup.trust/us/about-us/newsroom-and-events/blog/2011/february/double-hmac-verification/)。
除了每个散列的第二次HMAC散列之外,随机长度的随机盐被添加到两者中,以使散列定时/过程更难以预测。
我的实现看起来像这样:
function hmac_verify ($hash_original, $message, $key) {
$hmac_salt = '...'; // was added at the original HMAC signing
$random_salt = openssl_random_pseudo_bytes (rand(16,96));
$raw_hash = hash_hmac('sha512', $message . $hmac_salt, $key, true);
$hash_compare = base64_encode ($raw_hash); // $hash_original is in base64
$hash_compare_safe = hash_hmac('sha512', $hash_compare, $random_salt, true);
$hash_original_safe = hash_hmac('sha512', $hash_original, $random_salt, true);
if ($hash_compare_safe === $hash_original_safe) return true;
else return false;
}
在解密加密文本以验证解密结果后,以这种方式调用该函数:
if (!hmac_verify ($hmac_hash, $plaintext . $cipher_text, $key . $iv)) return "HASH ERROR";
这会成功阻止定时攻击吗?我做了什么不必要的事吗?有什么可以改进吗?
第二个问题是,对明文,密文或两者(如我的例子中)执行HMAC验证是否更为明智,以及原因。
答案 0 :(得分:1)
在我阅读你的功能时,我已经留下了一些内联评论。在阅读完整篇文章之后,这不是一个分析,而是我在阅读时立即想到的。
function hmac_verify ($hash_original, $message, $key) {
##
# Nitpick: A variable named $hash_original will prime people who read
# your code to think of simple hash functions rather than HMAC
##
$hmac_salt = '...'; // was added at the original HMAC signing
##
# What is this? $hmac_salt? Looks like a hard coded-salt (a.k.a. pepper).
# I wouldn't trust this with my life.
##
$random_salt = openssl_random_pseudo_bytes (rand(16,96));
##
# Why are you bothering to randomize this? Just use a static value
# approximating the output size of the hash function (i.e. 64).
##
$raw_hash = hash_hmac('sha512', $message . $hmac_salt, $key, true);
$hash_compare = base64_encode ($raw_hash); // $hash_original is in base64
$hash_compare_safe = hash_hmac('sha512', $hash_compare, $random_salt, true);
##
# Ah, yeah, don't pepper. HMAC is secure.
##
$hash_original_safe = hash_hmac('sha512', $hash_original, $random_salt, true);
if ($hash_compare_safe === $hash_original_safe) return true;
else return false;
##
# Why not just do this?
# return $hash_compare_safe === $hash_original_safe;
##
}
因此,我强烈建议将其分为两个独立的机制:一个计算MAC,另一个在常数时间内比较字符串(如PHP 5.6' s hash_equals()
)。
function hmac_verify ($hmac, $message, $key)
{
$calc = hash_hmac('sha512', $message, $key, true);
return hmac_equals($hmac, $calc);
}
function hmac_equals($hmac, $calc)
{
$random = openssl_random_pseudo_bytes(64);
return (
hash_hmac('sha512', $hmac, $random)
===
hash_hmac('sha512', $calc, $random)
);
}