在密码学中,定时攻击是一种侧通道攻击,其中 攻击者试图通过分析时间来破坏密码系统 用于执行加密算法。
实际上,为了防止时间攻击,我使用了this answer中的以下功能:
function timingSafeCompare($safe, $user) {
// Prevent issues if string length is 0
$safe .= chr(0);
$user .= chr(0);
$safeLen = strlen($safe);
$userLen = strlen($user);
// Set the result to the difference between the lengths
$result = $safeLen - $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($safe[$i % $safeLen]) ^ ord($user[$i]));
}
// They are only identical strings if $result is exactly 0...
return $result === 0;
}
但我在想是否有可能使用像
这样的随机睡眠来防止这种攻击function timingSafeCompare($a,$b) {
sleep(rand(0,100));
if ($a === $b) {
return true;
} else {
return false;
}
}
或者可能增加睡眠的随机性
sleep(rand(1,10)+rand(1,10)+rand(1,10)+rand(1,10));
这种方法可以完全防止定时攻击吗?或者只是让工作更努力?
答案 0 :(得分:14)
这种方法可以完全防止定时攻击吗?或者只是让工作更努力?
都不是。它不会阻止定时攻击,也不会使它们变得更加困难。
要了解原因,请查看docs for sleep。具体来说,第一个参数的含义:
以秒为单位暂停时间。
所以你的应用程序需要0.3秒才能无故障响应。睡眠时需要0.3,1.3,2.3等......
所以真的,要获得我们关心的部分(时序差异),我们只需要切掉整数部分:
$real_time = $time - floor($time);
但让我们更进一步。假设你使用usleep随机睡觉。这更加精细。那是在几微秒内睡觉。
嗯,测量是在15-50 纳米秒范围内进行的。因此,睡眠仍然比所进行的测量大约100倍<强> 粒度。所以我们可以平均到一微秒:
$microseconds = $time * 1000000;
$real_microseconds = $microseconds - floor($microseconds);
仍然有有意义的数据。
你可以更进一步,使用可以睡眠到纳秒级精度的time_nanosleep。
然后你可以开始拥抱这些数字。
但数据仍然存在。随机性的美妙之处在于你可以将其平均化:
$x = 15 + rand(1, 10000);
运行足够的时间,你会得到一个漂亮的漂亮图表。你会告诉大约有10000个不同的数字,所以你可以平均掉随机性并推断出“私人”15。
因为良好的随机性是无偏见的,所以很容易在足够大的样本上进行统计检测。
所以我要问的问题是:
答案 1 :(得分:9)
Anthony Ferrara在他的博客文章It's All About Time中回答了这个问题。我强烈推荐这篇文章。
很多人,当他们听到计时攻击时,会想“好吧,我只会添加一个随机的延迟!这样就行了!”。并it doesn't。
答案 2 :(得分:8)
如果攻击者可以观察到的唯一侧通道是响应时间,那么单个请求就可以了。
但是,如果攻击者发出足够的请求,则此随机延迟可能会按照@Scott's answer引用ircmaxell's blog post中的说明进行平均化:
因此,如果我们需要运行49,000次测试以获得15ns的准确度[没有随机延迟],那么我们需要大约100,000或1,000,000次测试,以获得相同的精度和随机延迟。或许100,000,000。但数据仍然存在。
作为一个例子,让我们估计定时攻击获得有效的160位会话ID(如PHP at 6 bits per character which gives a length of 27 characters)所需的请求数。假设,linked answer只能同时对一个用户进行攻击(因为他们将用户存储在cookie中查找)。
从博客文章100,000中获取最佳案例,排列数量为100,000 * 2^6 * 27
。
平均而言,攻击者会在排列数量的中途找到值。
这使得从定时攻击中发现会话ID所需的请求数为86,400,000。这与没有您提出的时间保护的42,336,000个请求进行比较(假设像博客文章那样准确度为15ns)。
在博客文章中,测试时间最长为14,平均花费0.01171秒,这意味着86,400,000需要1,011,744秒,相当于11天17小时2分24秒。
随机睡眠可以防止定时攻击吗?
这取决于使用随机睡眠的上下文,以及它保护的字符串的位强度。如果是为了#34;让我登录&#34;功能是链接问题中的上下文,那么攻击者花11天时间使用定时攻击来暴力破坏值是值得的。但是,这是假设完美的条件(即,对于每个测试的字符串位置,您的应用程序的响应时间相当一致,并且不会重置或转换ID)。此外,攻击者的这些类型的活动会产生很多噪音,很可能会通过IDS和IPS发现它们。
它无法完全阻止它们,但它可能使攻击者执行起来更加困难。使用像hash-equals
这样的东西会更容易也更好,它可以完全假设字符串长度相等,从而防止定时攻击。
function timingSafeCompare($a,$b) {
sleep(rand(0,100));
if ($a === $b) {
return true;
} else {
return false;
}
}
请注意,PHP rand
函数不是加密安全:
注意 此函数不会生成加密安全值,也不应用于加密目的。如果您需要加密安全值,请考虑改为使用
openssl_random_pseudo_bytes()
。
这意味着理论上攻击者可以预测rand
将要生成什么,然后使用此信息来确定应用程序的响应时间延迟是否是由于随机睡眠造成的。
接近安全性的最佳方法是假设攻击者知道您的源代码 - 攻击者唯一的秘密应该是密钥和密码之类的东西 - 假设他们知道所使用的算法和函数。如果您仍然可以说您的系统是安全的,即使攻击者确切地知道它是如何工作的,那么您将大部分都在那里。类似rand
的函数通常设置为当前时间种子,因此攻击者可以确保将其系统时钟设置为与服务器相同,然后发出请求以验证其生成器是否与您的生成器匹配。
因此,最好避免不安全的随机函数,例如rand
,并将您的实现更改为使用openssl_random_pseudo_bytes
,这将是不可预测的。
另外,根据ircmaxell的评论,sleep
不够精细,因为它只接受一个整数来表示秒数。如果您打算尝试这种方法,请使用随机数纳秒来查看time_nanosleep
。
这些指针应该有助于确保您的实施免受此类时间攻击。