Сроки атаки с PHP

Я пытаюсь произвести синхронизацию в 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);

Это поиск слова со следующими ограничениями

только до 10 символов

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

Есть ли что-то, что я делаю не так?

Скрипт зацикливается на длину, правильно определяет длину. Затем он повторяет каждую букву (az) и проверяет их скорость. Теоретически, "haaaa" должен быть немного медленнее, чем "aaaaa", поскольку первая буква ах, затем она продолжается для каждой из 5 букв.

Бег дает что-то вроде "brhas", что явно неправильно (каждый раз по-разному, но всегда неправильно)

1 ответ

Есть ли что-то, что я делаю не так?

Я так не думаю. Я попробовал ваш код, и я, как и вы, и другие люди, которые пробовали в комментариях, получают совершенно случайные результаты для второго цикла. Первый (длина) в основном надежный, хотя и не в 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, Проблема в том, что разница во времени сильно зависит от:

  1. реализация memcmp
  2. текущая нагрузка и мешающие процессы
  3. архитектура машины.

Я рекомендую эту статью под названием "Бенчмаркинг memcmp для синхронизации атак" для более подробных объяснений. Они сделали гораздо более точный тест и до сих пор не смогли получить четкую заметную разницу во времени. Я просто собираюсь процитировать заключение статьи:

В заключение, это сильно зависит от обстоятельств, если memcmp() подвержен временной атаке.

Другие вопросы по тегам