Заметки, Проекты → MD5 и скорость выборки
Пару дней назад завязался небольшой диалог в твиттере по поводу шифрования паролей в веб-сервисах. На фразу «кто не использует — идиот» мне ответили в стиле:
Шифрование создает сильную дополнительную нагрузку для веб-сервиса и большие проекты избегают подобного.
Подобное я слышу уже в сотый раз, поэтому решил сделать маленький тест и показать, что это абсолютно не верно и создатели этих сервисов (в которых важные данные, такие как пароли, номера карт и пр., не шифруются) полные идиоты.
Собственно, сам тест очень простой. Я создал таблицу, в которой 3 поля:
- id — привычка;
- str — данные в открытом виде (в тесте совпадает с id);
- 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 типа запросов:
- запрос по не хешированной строке;
- запрос по md5, хеширование внутри mysql;
- запрос по 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-х случаях:
- Регистрация — надо сохранить пароль;
- Авторизация — надо сравнить пароль и хеш.
Все! Много знаете сервисов, для которых 0.5 сек, при 10000 одновременных авторизаций и регистраций, большая цифра? )
Update: добавил цифры по SHA1. Хотелось еще добавить еще цифры по bcrypt, но уж очень долго работает данная функция в php, а встроенной в mysql нет. Поэтому, пришлось отложить bcrypt на будущее.