Может ли случайный сон предотвратить временные атаки?

От Wikipedia

В криптографии временная атака представляет собой атаку бокового канала, в которой злоумышленник пытается скомпрометировать криптосистему, анализируя время выполненных для выполнения криптографических алгоритмов.

На самом деле, чтобы предотвратить временные атаки, я использую следующую функцию, взятую из этого ответа:

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 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));

Этот подход может полностью предотвратить временные атаки? Или просто сделать работу сложнее?

Ответы

Ответ 1

Этот подход может полностью предотвратить временные атаки? Или просто сделать работу сложнее?

Ни. Он не предотвращает временные атаки и не делает их более трудными.

Чтобы понять, почему, посмотрите документы для сна. В частности, значение первого параметра:

Остановить время в секундах.

Итак, ваше приложение занимает 0,3 секунды, чтобы отвечать без сна. С сон он принимает 0,3, 1,3, 2,3 и т.д....

Итак, чтобы получить часть, о которой мы заботимся (разница во времени), нам просто нужно отрубить целую часть:

$real_time = $time - floor($time);

Но отпустите шаг вперед. Скажем, что вы случайно спали, используя usleep. Это намного более гранулированный. Это спать в микросекундах.

Ну, измерения выполняются во второй шкале 15-50 nano. Так что сон все еще примерно в 100 раз меньше зернисто, чем сделанные измерения. Таким образом, мы можем усреднить до одной микросекунды:

$microseconds = $time * 1000000;
$real_microseconds = $microseconds - floor($microseconds);

И все еще имеют значимые данные.

Вы можете пойти дальше и использовать time_nanosleep, который может спать с точностью до наносекундной шкалы.

Затем вы можете начинать fuddling с номерами.

Но данные все еще существуют. Красота случайности заключается в том, что вы можете просто усреднить ее:

$x = 15 + rand(1, 10000);

Запустите это достаточно, и вы получите красивый симпатичный график. Вы скажете, что существует около 10000 разных чисел, поэтому вы можете в среднем вычесть случайность и вывести "private" 15.

Поскольку доброкачественная случайность непредвзята, ее довольно легко обнаружить статистически на достаточно большом образце.

Итак, я задал вопрос:

Зачем беспокоиться о спящих хаках, когда вы можете исправить проблему правильно?

Ответ 2

Антони Феррара ответил на этот вопрос в своем блоге, It All About Time . Я настоятельно рекомендую эту статью.

Многие люди, когда они слышат о временных атаках, думают: "Ну, я просто добавлю случайную задержку! Это сработает!". И он не.

Ответ 3

Это отлично подходит для одного запроса, если единственным побочным каналом, наблюдаемым злоумышленником, является время отклика.

Однако, если злоумышленник делает достаточно запросов, эта случайная задержка может быть средней, как указано в @Scott answer, ссылаясь на сообщение в блоге ircmaxell:

Итак, если нам нужно было запустить 49 000 тестов, чтобы получить точность 15 нс [без случайной задержки], тогда нам понадобится, пожалуй, 100 000 или 1 000 000 тестов с одинаковой точностью со случайной задержкой. Или, может быть, 100 000 000. Но данные все еще существуют.

В качестве примера давайте оценим количество запросов, которые должны иметь временную атак, чтобы получить действительный 160-битный идентификатор сеанса, такой как PHP по 6 бит на символ, который дает длину 27 символов. Предположим, как связанный ответ , что атака может выполняться только на одного пользователя одновременно (поскольку они хранят пользователя для поиска в файле cookie).

Взяв самый лучший случай из сообщения в блоге, 100 000, количество перестановок будет 100,000 * 2^6 * 27.

В среднем, злоумышленник найдет значение на полпути через количество перестановок.

Это дает количество запросов, необходимых для обнаружения идентификатора сеанса от временной атаки до 86 400 000. Это сравнивается с 42 336 000 запросами без вашей предлагаемой временной защиты (при условии, что точность в 15 нс, как и в блоге).

В блоге, взяв самую длинную тестируемую длину, 14, в среднем составляло 0,01171 секунды, что означает, что 86 400 000 займет 1,011,744 секунды, что соответствует 11 дням 17 часов 2 минуты 24 секунды.

Может ли случайный сон предотвратить временные атаки?

Это зависит от контекста, в котором используется ваш случайный сон, и степени бита строки, которую она защищает. Если функция "сохранить меня вошла в систему", которая является контекстом в связанном вопросе, может стоить злоумышленнику потратить 11 дней на использование тактовой атаки для грубой силы. Тем не менее, это предполагает идеальные условия (т.е. Довольно последовательное время отклика из вашего приложения для каждой проверенной позиции строки и без сброса или опрокидывания идентификаторов). Кроме того, этот вид активности от злоумышленника создаст много шума, и, скорее всего, они будут обнаружены через 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 со случайным числом наносекунд.

Эти указатели должны помочь защитить вашу реализацию от такого типа синхронизации времени.