随机睡眠可以防止定时攻击吗?

DrK*_*Key 14 php security cryptography timing timing-attack

来自维基百科

在密码学中,定时攻击是一种侧信道攻击,攻击者通过分析执行加密算法所花费的时间来试图破坏密码系统.

实际上,为了防止定时攻击,我使用了以下从这个答案中获取的函数:

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;
}
Run Code Online (Sandbox Code Playgroud)

但我在想是否有可能使用随机睡眠来阻止这种攻击

function timingSafeCompare($a,$b) {
    sleep(rand(0,100));
    if ($a === $b) {
        return true;
    } else {
        return false;
    }
}
Run Code Online (Sandbox Code Playgroud)

或者可能增加睡眠的随机性

sleep(rand(1,10)+rand(1,10)+rand(1,10)+rand(1,10));
Run Code Online (Sandbox Code Playgroud)

这种方法可以完全防止定时攻击吗?或者只是让工作更难?

irc*_*ell 15

这种方法可以完全防止定时攻击吗?或者只是让工作更难?

都不是.它不会阻止定时攻击,也不会使它们变得更加困难.

要了解原因,请查看睡眠文档.具体来说,第一个参数的含义:

以秒为单位暂停时间.

所以你的应用程序需要0.3秒才能无需睡眠即可响应 睡眠时需要0.3,1.3,2.3等......

所以,真的,要获得我们关心的部分(时序差异),我们只需要切掉整数部分:

$real_time = $time - floor($time);
Run Code Online (Sandbox Code Playgroud)

但让我们更进一步.假设您使用usleep随机睡觉.这更加精细.那是在几微秒内睡觉的.

那么,测量是在15-50 纳秒的尺度下进行的.因此,睡眠的粒度仍然比测量值 100倍.所以我们可以平均到单微秒:

$microseconds = $time * 1000000;
$real_microseconds = $microseconds - floor($microseconds);
Run Code Online (Sandbox Code Playgroud)

并且仍然有有意义的数据.

你可以进一步使用time_nanosleep,它可以睡到纳秒级精度.

然后你可以开始拥抱这些数字.

但数据仍然存在.随机性的美妙之处在于你可以将其平均化:

$x = 15 + rand(1, 10000);
Run Code Online (Sandbox Code Playgroud)

运行足够的时间,你会得到一个漂亮的漂亮图表.你会告诉大约有10000个不同的数字,所以你可以平均掉掉随机性并推断出"私有"15.

由于良好的随机性是无偏的,因此在足够大的样本上进行统计检测非常容易.

所以我要问的问题是:

当你可以正确解决问题时,为什么要打扰睡眠般的黑客?

  • 我喜欢我在其他答案中引用的帖子的作者,他们比我更高的投票:-P ...(只是玩,实际上是非常荣幸) (2认同)

Sco*_*ski 9

安东尼费拉拉在他的博客文章" 这就是时间关系"中回答了这个问题.我强烈推荐这篇文章.

许多人,当他们听到定时攻击时,会想"好吧,我只会添加一个随机延迟!那就行了!".而且它没有.

  • @ Phil_1984_ 1)粒度.大多数"随机"睡眠是在毫秒级别,我们测量的差异在10纳秒级别.2)地方.硬件上的代理可以观察CPU负载并通过活动(在VM等中)告知睡眠.3)统计上,那些随机睡眠可以被平均掉.4)这是一个绑带.这不是缓解,它不会堵塞潜在的伤口,它只是让它无法看到它.这是默默无闻的. (2认同)

Sil*_*Fox 8

如果攻击者可观察到的唯一侧通道是响应时间,则这对于单个请求是好的.

但是,如果攻击者发出足够的请求,这个随机延迟可以按照@ Scott的回答中所述,并引用ircmaxell的博文:

因此,如果我们需要运行49,000次测试以获得15ns的准确度[没有随机延迟],那么我们需要大约100,000或1,000,000次测试,以获得相同的精度和随机延迟.或许100,000,000.但数据仍然存在.

例如,让我们估计一个定时攻击所需的请求数,以获得有效的160位会话ID,如PHP ,每个字符6位,长度为27个字符.假设,与链接的答案一样,攻击只能同时对一个用户进行(因为他们将用户存储在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秒.

随机睡眠可以防止定时攻击吗?

这取决于使用随机睡眠的上下文,以及它保护的字符串的位强度.如果它是"让我登录"功能,这是链接问题中的上下文,那么攻击者花费11天时间来使用定时攻击来暴力破坏值可能是值得的.但是,这是假设完美的条件(即,对于每个测试的字符串位置,您的应用程序的响应时间相当一致,并且不会重置或转换ID).此外,攻击者的这些类型的活动会产生很多噪音,很可能会通过IDS和IPS发现它们.

它不能完全阻止它们,但它可能使攻击者更难以执行.使用像hash-equals防止定时攻击完全假设字符串长度相等的东西会更容易和更好.

你提出的代码

function timingSafeCompare($a,$b) {
    sleep(rand(0,100));
    if ($a === $b) {
        return true;
    } else {
        return false;
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,PHP rand函数不具有加密安全性:

注意此函数不会生成加密安全值,也不应用于加密目的.如果您需要加密安全值,请考虑使用openssl_random_pseudo_bytes().

这意味着理论上攻击者可以预测rand将要生成的内容,然后使用此信息来确定应用程序的响应时间延迟是否是由于随机睡眠造成的.

处理安全性的最佳方法是假设攻击者知道您的源代码 - 攻击者唯一的秘密应该是密钥和密码之类的东西 - 假设他们知道所使用的算法和函数.如果您仍然可以说您的系统是安全的,即使攻击者确切地知道它是如何工作的,那么您将大部分都在那里.类似rand的函数通常设置为当前时间的种子,因此攻击者可以确保将其系统时钟设置为与服务器相同,然后发出请求以验证其生成器是否与您的生成器匹配.

因此,最好避免使用不安全的随机函数rand,并将您的实现改为使用openssl_random_pseudo_bytes,这将是不可预测的.

另外,根据ircmaxell的评论,sleep它不够精细,因为它只接受一个整数来表示秒数.如果您打算尝试这种方法,请time_nanosleep使用随机数纳秒.

这些指针应该有助于保护您的实现免受此类时序攻击.