Заметки, Проекты → MD5 и скорость выборки

Пару дней назад завязался небольшой диалог в твиттере по поводу шифрования паролей в веб-сервисах. На фразу «кто не использует — идиот» мне ответили в стиле:

Шифрование создает сильную дополнительную нагрузку для веб-сервиса и большие проекты избегают подобного.

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

Собственно, сам тест очень простой. Я создал таблицу, в которой 3 поля:

  1. id — привычка;
  2. str — данные в открытом виде (в тесте совпадает с id);
  3. pass — хешированные данные (md5(id)).

Таблицу заполнил 10000-ми строками. Теперь сами тесты:

mysql_connect('openserver', 'root', NULL) or die('err connect');
mysql_select_db('md5') or die('err select db');

$start = microtime(TRUE);
for($i=1;$i<=10000;$i++)
{
mysql_query('SELECT FROM `str` WHERE `str`="'.$i.'" LIMIT 1');
//    mysql_query('SELECT FROM `str` WHERE `pass`=MD5("'.$i.'") LIMIT 1');
//    mysql_query('SELECT FROM `str` WHERE `pass`="'.md5($i).'" LIMIT 1');
}

echo microtime(TRUE) - $start;

Из кода видно, что я проверяю 3 типа запросов:

  1. запрос по не хешированной строке;
  2. запрос по md5, хеширование внутри mysql;
  3. запрос по md5, хеширование в php.

Каждый запрос выполнялся в цикле по 10000 раз, по 10 запусков теста для каждого запроса. Вот результаты:

Без хеша MD5 в mysql MD5 в php SHA1 в mysql SHA1 в php
1 0.790827035904 0.819698095322 0.809172868729 0.84441113472 0.880232095718
2 0.854579210281 0.825169086456 0.847054004669 0.911170005798 0.914683818817
3 0.805845975876 0.814687013626 0.850682020187 0.880912065506 0.898703098297
4 0.79811000824 0.811382055283 0.878005027771 0.867966175079 0.909711122513
5 0.83246588707 0.795244932175 0.875553131104 0.866142988205 0.896888971329
6 0.823527097702 0.826287031174 0.838028907776 0.877794981003 0.89293718338
7 0.799317121506 0.805939912796 0.891763210297 0.865235090256 0.927887916565
8 0.801607131958 0.811107158661 0.845654964447 0.8707010746 0.909883975983
9 0.793571949005 0.799591064453 0.89443397522 0.849224805832 0.893163204193
10 0.806991815567 0.815193891525 0.892179965973 0.831253051758 0.882263898849
среднее 0.810684323311 0.812430024147 0.862252807617 0.866481137276 0.900635528564

Уверен, что Вы уже и сами все поняли, но все-же обобщу результаты: разница между запросом к не хешированным данным и хеширование в самом запросе — 0.002 секунды на 10000 запросов, т.е. 0.0000002 сек на запрос на ноутбуке не первой свежести. Даже если хешировать данные в коде, разница получится 0.000006 сек на запрос.

Уже слышу, как меня упрекают в том, что в нагруженных проектах эти цифры значительно увеличатся. Не верю! (с) Станиславский.

А не верю по той причине, что ни один разработчик (тем более в крупном проекте) не будет делать подобные запросы постоянно. Чаще всего информация о пользователе лежит в сессии/куках, вместе с уже хешированным паролем. Это значит, что запросы будут идти по без хеширования. Шифрование-же применяется, обычно, в 2-х случаях:

  1. Регистрация — надо сохранить пароль;
  2. Авторизация — надо сравнить пароль и хеш.

Все! Много знаете сервисов, для которых 0.5 сек, при 10000 одновременных авторизаций и регистраций, большая цифра? )

Update: добавил цифры по SHA1. Хотелось еще добавить еще цифры по bcrypt, но уж очень долго работает данная функция в php, а встроенной в mysql нет. Поэтому, пришлось отложить bcrypt на будущее.