Я пытаюсь произвести синхронизацию атаки в php
Использование php 7.1 со следующим скриптом
<?php
$find = "hello";
$length = array_combine(range(1, 10), array_fill(1, 10, 0));
for ($i = 0; $i < 1000000; $i++) {
for ($j = 1; $j <= 10; $j++) {
$testValue = str_repeat('a', $j);
$start = microtime(true);
if ($find === $testValue) {
//do Nothing
}
$end = microtime(true);
$length[$j] += $end - $start;
}
}
arsort($length);
$length = key($length);
var_dump($length . " found");
$found = '';
$alphabet = array_combine(range('a', 'z'), array_fill(1, 26, 0));
for ($len = 0; $len < $length; $len++) {
$currentIteration = $alphabet;
$filler = str_repeat('a', $length - $len - 1);
for ($i = 0; $i < 1000000; $i++) {
foreach ($currentIteration as $letter => $time) {
$testValue = $found . $letter . $filler;
$start = microtime(true);
if ($find === $testValue) {
//do Nothing
}
$end = microtime(true);
$currentIteration[$letter] += $end - $start;
}
}
arsort($currentIteration);
$found .= key($currentIteration);
}
var_dump($found);
Это поиск слова со следующими ограничениями
только a-z
до 10 символов
Сценарий находит длину слова без проблем, но значение слова никогда не возвращается, как ожидалось при временной атаке.
Есть ли что-то, что я делаю не так?
Скрипт зацикливается на длину, правильно определяет длину. Затем он проходит по каждой букве (a-z) и проверяет их скорость. Теоретически «haaaa» должен быть немного медленнее, чем «aaaaa» из-за того, что первая буква является h, затем он продолжается для каждой из 5 букв.
Бег дает что-то вроде «brhas», что явно неправильно (каждый раз по-разному, но всегда неправильно)
Есть ли что-то, что я делаю не так?
Я так не думаю. Я попробовал ваш код, и я, как и вы, и другие люди, которые пробовали в комментариях, получают совершенно случайные результаты для второго цикла. Первый (длина) в основном надежен, хотя и не в 100% случаев. Кстати, $argv[1]
предложенный трюк на самом деле не улучшил согласованность результатов, и, честно говоря, я не очень понимаю, почему это так.
Поскольку мне было любопытно, я взглянул на исходный код PHP 7.1. Функция идентификации строки (zend_is_identical
) выглядит так:
case IS_STRING:
return (Z_STR_P(op1) == Z_STR_P(op2) ||
(Z_STRLEN_P(op1) == Z_STRLEN_P(op2) &&
memcmp(Z_STRVAL_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op1)) == 0));
Теперь легко понять, почему первая временная атака на длину прекрасно работает. Если длина отличается, то memcmp
никогда не вызывается и поэтому возвращается намного быстрее. Разница легко заметна даже без слишком большого количества итераций.
Как только вы определили длину, во втором цикле вы пытаетесь атаковать memcmp
, Проблема в том, что разница во времени сильно зависит от:
memcmp
Я рекомендую эту статью под названием «Бенчмаркинг memcmp для синхронизации атак» для более подробных объяснений. Они сделали гораздо более точный тест и до сих пор не смогли получить четкую заметную разницу во времени. Я просто собираюсь процитировать заключение статьи:
В заключение, это сильно зависит от обстоятельств, если
memcmp()
подвержен временной атаке.
Других решений пока нет …