Pull to refresh

Безопасность это не просто

Reading time3 min
Views664
Original author: Laurent Bachelier
Здраствуйте.

Представляю вам перевод довольно интересной статьи, которую я нашел пытаясь исправить баг в sfDoctrineGuardPlugin. К счастью недели 2 назад все написаное здесь уже исправили и безопасности ничего не угрожает, но хочу обратить внимание тех, кто не так часто следит за обновлением плагинов и возможно не знает об этой уязвимости.


Последнее обновление: Через год(прим. переводчика: после первой публикации об ошибке ), оба плагина, наконец, обновлены и используют более качественный генератор случайных ключей.

Безопасность это не просто. Программисты должны оставить такие вещи, как генерацию случайных чисел и идентификаторов готовым библиотекам (или, по крайней мере, разработать лучший способ). Многие проекты освоили это с трудом.

Поговорим об этом, на примере функции, которую я встретил около 6 месяцев назад:
  1. function generateRandomKey($len = 20)
  2. {
  3.   $string = '';
  4.   $pool = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
  5.   for ($i = 1; $i < = $len; $i++)
  6.   {
  7.     $string .= substr($pool, rand( 0, 61), 1);
  8.   }
  9.  
  10.   return md5($string);
  11. }
  12.  

Это настоящая жемчужина, как кажется, она была написана, чтобы сосредоточить все, что программист не должен делать.
Ошибка 1
Использование rand() вместо mt_rand(). Любой PHP программист должен знать это.
Ошибка 2
Использование md5() вместо sha1(). Любой PHP программист должен знать это.
Ошибка 3
Создание 20ти символьной случайной строки, а затем ее хэширование в 32 символьную строку, выглядит немного глупо. Конечно, хэш содержит меньше различных символов, но все-таки на входе мы имеем 7.04423e +35 различных значений, а на выходе можем иметь 3.40282e +38.
Ошибка 4
Вызов rand() несколько раз. Это обозначает большое пренебрежение к тому, как работают псевдо-генераторы случайных чисел. До тех пор, пока не изменится источник, будет возможно легко угадывать какое будет следующее число в зависимости от предыдущих. Оно не будет «более случайным» при многократных вызовах функции.
Ошибка 5
Использование сильно ограниченного диапазона для выбора случайных чисел. Кроме того, для чего выбирать буквенно-цифровые символы, если вы не используете их после того как они перешли в функцию хеширования? Похоже, что это очень плохо продумано.
Ошибка 6
Использование в качестве строки для md5 буквенно-цифровых символов, присутствующих во всех существующих радужных таблицах.
Ошибка 7
Никогда не слышали о chr()?
Ошибка 8
Зачем изобретать велосипед? В крайнем случае, если у вас есть на это причина, напишите об этом (эта функция не нуждается в комментариях).

Даже без проверки результатов, любой программист должен знать, что эту функцию надо полностью переписать.

Давайте посмотрим, как она должна была выглядеть.
  1. function generateRandomKey()
  2. {
  3.   return base_convert(sha1(uniqid(mt_rand(), true)), 16, 36);
  4. }

Как я дошел до этого? В основном, читая документацию к PHP, и не создавая генераторов случайных чисел, а используя один.

Использование base_convert() на самом деле не важно, в основном потому, что поле базы данных было слишком коротким (ничего не теряется от sha1()). На самом деле было бы лучше без sha1(), мы ее используем только для красоты.

uniqueid() берет полученное от mt_rand() значение и прибавляет к нему случайное уникальное значение(но предсказуемого диапазона, есть смысл использовать обе функции). Это рекомендуется документацией к PHP и этого более чем достаточно.

Теперь вы, вероятно, спросите себя, где я нашел этот кусок кода.

Функция находится в sfGuardPlugin и sfDoctrineGuardPlugin для symfony framework. Эта функция здесь почти с самого начала, хотя было хуже. Таковы на сегодняшний день наиболее часто используемые плагины, одобренные официальной документацией.

Что это значит? На некоторых системах, будет очень просто войти в систему под видом любого пользователя, используя брут-форс. Или пользователь может случайно войти в качестве другого, так как вероятность коллизии весьма высока.

Ну, если это реально, кто-то должен был заметить это! Я, вероятно, не злоумышленник.
На самом деле, это так. У меня была возможность воспроизвести все это на старом Debian сервере, и на этом сервере был сайт, где пользователи много раз жаловались на то что, заходят в качестве другого пользователя(надеюсь, этот сервер вышел из строя и проект в настоящее время работает на с исправленной функцией). Я также попытался воспроизвести ее на виртуальной машине под Windows XP(так как он был самый простой способ получить PHP с недостатками генератора случайных чисел), с успехом, конечно же. Поскольку на этих двух машинах я получил много коллизий, то скорей всего даже на более совершенных системах ошибка может быть использована с некоторым усилием.

Почему я это делаю?
Потому что я сообщил об этом шесть месяцев назад, но этому было уделено мало внимания.
Думаю что, symfony это замечательно, но безопасность оставляет желать лучшего (хотя другие мои замечания касаются больше стандартного программирования или практики с хостингом, воодушевленные symfony а не кодом).


По данной теме есть еще один пост где приведен пример работы чудо-функции.
Tags:
Hubs:
+2
Comments7

Articles

Change theme settings