Блог


Пуд соли (рассуждения о криптографии)

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

Я не претендую на роль гуру в ней, более того, я со всей ответственностью заявляю, что ничего по большому счету в криптографии не понимаю.  

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

Давайте рассмотрим внимательно, что написано в википедии. 

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

Это факт, но из дальнейшего текста видно, что солью нам пытаются представить только индивидуальный для каждого пароля набор дополнительных символов. Хотя по сути соль использовалась еще на заре компьютеризации, когда мощности машин не позволяли сколь-нибудь рентабельно отбрутить самый простой алгоритм хэширования - md5. C увеличением производительности компьютеров простой md5 хэш стал совершенно бесполезен. И вот тогда появилась соль. Соль использовалась для увеличения длины исходной строки, ибо чем она длиннее, тем сложнее и долговременнее подбор, так как первые системы часто хранили хэши в открытом виде для использования разными сервисами. Динамическая (индивидуальная) соль использовалась исключительно для защиты одинаковых паролей, но в закрытых системах применялась и статическая. Только потом, с изобретением в 2003 году алгоритма радужных таблиц, динамическая соль стала актуальной для защиты. Но она вовсе не отменила статическую.

Правда сейчас её иногда называют "секретный ключ", что на мой взгляд не отражает сути. Но не это важно. Важно то, что автор статьи этот момент считает излишним и даже вредным.


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

В статье прямым текстом сказано:

Помните — соль не защищает один конкретный хеш от перебора, поэтому нет цели прятать соль — она хранится в открытом виде рядом с хешем. Задача соли — спасти набор украденных хешей, "удлинняя" пароль, а сделать она это может только в том случае, если у каждого хеша будет своя соль. Поэтому мы храним соль рядом с хешем и для каждого хеша генерируем свою уникальную последовательность символов соли.


Так вот, соль бывает разная. Секретная, общая для всех и хранящаяся вне базы данных, и динамическая, уникальная, вернее индивидуальная, для каждого пароля. И вот первая как раз и защищает один конкретный хэш от перебора. Автор недвузначно заявляет:

в реальных проектах следует применять только случайные соли, сгенерированные каким-либо ГПСЧ.


И это на мой взгляд в корне неверный подход. И хотя принцип использования статической соли очень близок к принципу "security by obscurity" ("безопасность маскировкой"), но если он используется плюсом к основному, это плюс и есть. Как говорится, безопасности много не бывает.

Но обобщим позже, сейчас немного пробежимся по рекомендациям автора статьи к использованию алгоритмов хэширования пароля. Он предлагает не мудрствуя лукаво использовать штатную функцию PHP crypt() Да, соглашусь, она вполне надежна.

Но надежна она только на сегодняшний день и то в новых версиях PHP, не ниже 5.3.7. Совершенно не ясно, что придумают хакеры завтра и на сколько еще возрастет быстродействие и мощность компьютеров. Ведь прямо в этой же статье есть конкретный намек, которого автор так и не понял Вот:

В 2012 году Poul-Henning Kamp призвал полностью отказаться от созданного им алгоритма, как не обеспечивающего в современных условиях ощутимого увеличения времени вычисления хеша, а значит, и не защищающего от полного перебора

Да, алгоритм продержался 18 лет, но ведь и развитие техники идет не линейно. Еще не успели из ларьков пропасть CDR, а уже свободно продаются флэшки на 64Gb. Несколько лет назад это было фантастикой.

Но не в этом даже суть. Сам Пол-Хеннинг в своей питиции отказа от алгоритма Md5crypt дал конкретный и четкий совет:

On a state of the art COTS computer, the algorithm should take at the very least 0.1 second (100 milliseconds) when implemented in software, preferably more.

Some kind of “round count” parameter should be made run-time tweakable so that the runtime/complexity can be increased over time by system administrators.

All major internet sites, anybody with more than 50.000 passwords, should design or configure a unique algorithm (consisting of course of standard one-way hash functions like SHA2 etc) for their site, in order to make development of highly optimized password brute-force technologies a “per-site” exercise for attackers.


Что в вольном переводе звучит примерно так:

На самых современных компьютерах алгоритм должен срабатывать не быстрее, чем 0,1 секунды (100 миллисекунд), а лучше дольше.

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

Все крупные интернет-сайты, имеющий более 50.000 паролей, должны разработать или настроить уникальный алгоритм (состоящий из нескольких стандартноых односторонних хэш-функции, таких как SHA2 и т.д.), для того, чтобы подобрать пароль перебором было серьёзной задачей для нападающих.

А этот человек знает, о чем говорит.

Что мы имеем, применив функцию crypt() в голом виде.
1. Скорость срабатывания функции на моем древнем ноутбуке(!), при скремблировании пароля длиной в 8 символов и самым "тяжелым" алгоритмом SHA-512 составляет всего 
0.016 с, что в 10 раз быстрее рекомендуемой.
2. Мы не можем использовать несколько различных алгоритмов хэширования.

Отсюда напрашивается вывод - функция нуждается в обертке. Ну или в собственной реализации алгоритма. Что напрочь отрицается автором статьи в википедии.

А теперь попробуем резюмировать эти рассуждения, пофантазировав, и поставив себя на место хакера. Допустим мы имеем форум, где большая посещаемость и большая база пользователей. И вот нам каким то хитрым способом в руки попадает база данных. Способов много, SQL-инъекции, несанкционированное удаленное подключение к серверу SQL, рабочий бэкап сперли наконец, мало ли. Так вот. Мы имеем базу данных, где хранятся хэши паролей, полученные с помощью алгоритма crypt() и индивидуальные соли. Но не имеем доступа к исходникам PHP.

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

Дело в том, что брутфорс, радуги и словари и другие способы переборов сегодня не так уж и актуальны. Современные способы защиты сводят эти алгоритмы на нет. Сегодня хакеры больше смотрят в сторону социальной инженерии. И им совершенно не нужно тратить машиноресурсы для получения всех паролей. Эти пароли в большей частью уже не актуальны. Из 20000, зареганных на форуме за допустим пять лет посетителей, процентов 90 как минимум уже забыли не то что пароли, вообще о существовании форума, а то и интернета в целом. Ну и на кой хакеру это старьё?

Нормальный взломщик хочет получить свежак. А свежак можно получить очень просто. Ломаем один хэш. Один единственный. Тот, который никак не защищен, если мы пользовались рекомендациями автора статьи. А именно получаем пароль администратора. Сделать это совершенно не сложно, если он захэширован голой функцией crypt()

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

Не буду рассказывать тонкостей, но это конкретная уязвимость, при определенном старании позволяющая спокойно собрать все свежие, актуальные  пароли. Обнуляем куки и терпеливо ждем, когда ничего не подозревающий пользователь введет свой родимый пароль в чистом виде.

Никаких брутфорсов, никаких потуг с линейкой графических машин, ни че го. Сиди и собирай урожай. И ведь даже ни кто ничего не заподозрит. Это называется "троян".

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

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

Первое. Доступы в админ-панель не должны находиться в базе данных. Только в конфиге. Если жулик добрался до конфиги - сайт уже в его руках, не важно где пароль. А если у него только база данных, еще нужно посмотреть что он сможет.

Если эта рекомендация невозможна по ряду причин, пользуйтесь этой функцией. Она отвечает всем требованиям безопасности.
1. Функция не использует собственных алгоритмов хэширования, а выстраивает последовательность штатных, проверенных алгоритмов. 
2. Скорость при дефолтных 5000 итераций и 8-символьном пароле на моем ноуте - 0,6с. Я понимаю, что использоваться будут не ноуты и даже не PHP, но и этого вполне достаточно.
3. Есть возможность одним движением увеличить число итераций, а значит время исполнения алгоритма.
4. Есть возможность самому настроить алгоритм хэширования, который не будет известен хакеру, получившему окольными путями базу данных.

Ну или если не по вкусу велосипеды, пользуйтесь crypt() в чистом виде, но только с умом. Используя большое количество раундов, не меньше миллиона. Тогда есть шанс, что и один пароль отбрутить будет непомерно сложной задачей. Ну и проверьте версию PHP.

И главное, лейтмотив сего эссе - используйте не только индивидуальную соль. Желательно пользоваться еще и общей, секретной, к которой нет доступа из бд.

Тогда без доступа к исходникам PHP, а именно к конфигурационному файлу, база паролей - бессмысленный набор букав, абра-кадабра. И пароль администратора не исключение. 

И последний совет. Помните - враг не дремлет. Не нужно верить ни кому в отдельности. Ни википедиям, ни таким вот моим статейкам. Вы один на один с хакером, если не наймете специалиста. Криптография - штука крайне сложная и непредсказуемая. Лучше ей не заниматься. И уж тем более не хватать верхушек из сомнительных источников, статус которого википедия в очередной раз подтвердила лично для меня.

 

 

Николай aka twin

 

Теги: Флейм

Комментарии (4)

Savage
27-07-2013
"Первое. Доступы в админ-панель не должны находиться в базе данных. Только в конфиге. Если жулик добрался до конфиги - сайт уже в его руках, не важно где пароль. А если у него только база данных, еще нужно посмотреть что он сможет."

Не понял смысл. В БД надо хранить доступ в админ-панель для лучшей безопасности?
twin
27-07-2013
Наоборот. Если есть возможность, пароль администратора лучше хранить в конфигурационном файле. Потому что получив доступ к базе данных, но не получив доступ к файлам, взломщик не узнает пароль и не попадет в админку.
Имя
30-07-2013
Боже, какая чушь. Не совестно такое нести?
Сайты сейчас это не статические странички с отдельным скриптом админки для админа... А с кучей пользователей, у которых свои роли на сайте, разные доступы.
В каком вы веке продолжаете жить?
twin
30-07-2013
Речь идет о пароли администратора, у которого полный доступ. Обычно на сайте таких всего несколько человек. У остальных модераторов свои полномочия. Вот их может быть много, с разными ролями. Но не с доступами к системным настройкам ресурса. FTP же ни кто не додумался раздавать модераторам. Так и тут.

Ну и это вы конечно не прочитали:
Если эта рекомендация невозможна по ряду причин, пользуйтесь этой функцией.

 
Наверх