Я просто встретил этот код в библиотеке HTTP Auth Zend Framework. Кажется, что используется специальная функция сравнения строк, чтобы сделать ее более безопасной. Однако я не совсем понимаю комментарии. Может ли кто-нибудь объяснить, почему эта функция более безопасна, чем делать $a == $b
?
/** * Securely compare two strings for equality while avoided C level memcmp() * optimisations capable of leaking timing information useful to an attacker * attempting to iteratively guess the unknown string (eg password) being * compared against. * * @param string $a * @param string $b * @return bool */ protected function _secureStringCompare($a, $b) { if (strlen($a) !== strlen($b)) { return false; } $result = 0; for ($i = 0; $i < strlen($a); $i++) { $result |= ord($a[$i]) ^ ord($b[$i]); } return $result == 0; }
Похоже, они пытаются предотвратить атаки времени .
В криптографии временная атака представляет собой атаку бокового канала, в которой злоумышленник пытается скомпрометировать криптосистему, анализируя время, затраченное на выполнение криптографических алгоритмов. Каждая логическая операция в компьютере требует времени для выполнения, и время может отличаться в зависимости от ввода; с точными измерениями времени для каждой операции, злоумышленник может работать обратно на вход.
В принципе, если для сравнения правильного пароля и неправильного пароля требуется другой промежуток времени, вы можете использовать время, чтобы выяснить, сколько символов пароля вы правильно поняли.
Рассмотрим крайне ошибочное сравнение строк (это в основном нормальная функция равенства строк, с очевидным wait
):
function compare(a, b) { if(len(a) !== len(b)) { return false; } for(i = 0; i < len(a); ++i) { if(a[i] !== b[i]) { return false; } wait(10); // wait 10 ms } return true; }
Скажем, вы даете пароль, и он (последовательно) занимает некоторое время для одного пароля и более 10 мс для другого. Что это говорит вам? Это означает, что второй пароль имеет еще один символ, отличный от первого.
Это позволяет вам взломать фильм – где вы угадываете пароль по одному символу за раз (что намного проще, чем угадывать каждый возможный пароль).
В реальном мире есть и другие факторы, поэтому вам приходится много раз проверять пароль, чтобы справляться с случайностью реального мира, но вы все равно можете попробовать каждый персональный пароль, пока, очевидно, не дойдете дольше, а затем начните с двух символьный пароль и т. д.
Эта функция по-прежнему имеет незначительную проблему:
if(strlen($a) !== strlen($b)) { return false; }
Он позволяет использовать временные атаки для определения правильной длины пароля, что позволяет не догадываться о более коротких или более длинных паролях. В общем, вы хотите сначала перенести свои пароли (что будет создавать строки с равной длиной), поэтому я предполагаю, что они не считают это проблемой.