Из Википедии
В криптографии временная атака представляет собой атаку бокового канала, в которой злоумышленник пытается скомпрометировать криптосистему, анализируя время, затраченное на выполнение криптографических алгоритмов.
На самом деле, чтобы предотвратить временные атаки, я использую следующую функцию, взятую из этого ответа :
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,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.
Поскольку добросовестная случайность непредвзята, ее довольно легко обнаружить статистически на достаточно большом образце.
Поэтому я задал вопрос:
Энтони Феррара ответил на этот вопрос в своем блоге « It's All About Time» . Я настоятельно рекомендую эту статью.
Многие люди, когда они слышат о временных атаках, думают: «Ну, я просто добавлю случайную задержку! Это сработает!». И это не так .
Это нормально для одного запроса, если единственным наблюдаемым атакующим боковым каналом является время отклика.
Однако, если злоумышленник делает достаточно запросов, эта случайная задержка может усреднить, как указано в ответе @ Скотта, ссылаясь на сообщение ircmaxell в блоге :
Поэтому, если нам нужно было выполнить 49 000 тестов, чтобы получить точность 15 нс [без случайной задержки], тогда нам понадобится, пожалуй, 100 000 или 100 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 017 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; } }
Обратите внимание, что функция rand
PHP не является криптографически безопасной:
Внимание. Эта функция не генерирует криптографически защищенные значения и не должна использоваться для криптографических целей. Если вам требуется криптографически безопасное значение,
openssl_random_pseudo_bytes()
вместо этого использоватьopenssl_random_pseudo_bytes()
.
Это означает, что теоретически злоумышленник может предсказать, что rand
собирался генерировать, а затем использовать эту информацию, чтобы определить, была ли отсрочка ответа от вашего приложения вызвана случайным сном или нет.
Лучший способ приблизиться к безопасности – предположить, что злоумышленник знает ваш исходный код – единственное, что секрет от злоумышленника – это такие вещи, как ключи и пароли, – предположите, что они знают используемые алгоритмы и функции. Если вы все еще можете сказать, что ваша система защищена, даже если злоумышленник точно знает, как это работает, вы будете в основном там. Такие функции, как rand
, обычно устанавливаются для посева с текущим временем суток, поэтому злоумышленник может просто удостовериться, что их системные часы установлены так же, как ваш сервер, а затем делают запросы на подтверждение того, что их генератор соответствует вашим требованиям.
Из-за этого лучше избегать небезопасных случайных функций, таких как rand
и изменить вашу реализацию, чтобы использовать openssl_random_pseudo_bytes
которые будут непредсказуемыми.
Кроме того, согласно комментарию ircmaxell, sleep
не является достаточно узким, поскольку он принимает только целое число, представляющее количество секунд. Если вы попытаетесь использовать этот подход, загляните в time_nanosleep
со случайным числом наносекунд.
Эти указатели должны помочь защитить вашу реализацию от такого типа синхронизации времени.