Как выбрать соль для хэш-функции, предназначенной для защиты паролей?
Я (почти полный) новичок, и это мой первый набег на шифрование - на самом деле это, наверное, в первый раз, когда я использую это слово.
Вот мой вопрос: для небанковского/военного или даже коммерческого веб-приложения, какой правильный способ выбрать соль для хэш-функции, используемой для паролей?
Я могу легко генерировать псевдослучайную соль для каждого нового пользователя и добавлять эту соль к их pw перед применением хэш-функции. Но мне все еще нужно хранить соль, поэтому, возможно, все, кто получает доступ к хешированным паролям, также получают соли.
Преимущество соли просто сделать pw "более случайным" и, следовательно, победить стандартные таблицы радуги на основе словаря?
Будет ли любая из следующих хороших и практических идей:
- Храните соль в отдельном db - возможно, отдельную систему, определенно другую хост, имя, pw и т.д.
- Генерировать соль на основе хэша имени пользователя (или сначала + фамилию, или дату регистрации), предположительно используя другую хеш-функцию? Тогда сама соль не будет храниться в db - только данные, используемые для ее вычисления, будут...
- Хранить в db значение, которое объединяет хешированный pw и соль, неявным образом (например, соль имеет 10 случайных ключей, и они вводятся внутри хэшированного pw между буквами 1 и 2, 4 и 5, 8 и т.д.).
Как побочный вопрос, насколько легко изменить алгоритм соленого хеша при обновлении программного обеспечения веб-сайта? Он чувствует себя кошмаром прямо сейчас.
Ответы
Ответ 1
- Упрощает проверку паролей - не рекомендуется.
- Лучше всего создать случайное число (возможно, 64-бит).
- См. (частично) SO 1191112. Соль не должна быть секретной; он просто должен быть другим.
Чтобы ответить на ваш вопрос: также запишите идентификатор алгоритма (возможно, простое число, возможно, строку имени) вместе с данными. По мере обновления вы добавили новые пароли, используя новый, предпочтительный алгоритм, но вы сохранили старый алгоритм, пока все не изменили свой пароль и не сохранились пароли, используя старый алгоритм. Опять же, это не должно быть секретным - это просто позволяет вам адаптироваться к изменениям в мире. Ясно, что если старый алгоритм внезапно оказывается бесполезным, вы думаете о том, можно ли использовать инкрементный подход. Но, если что-то такое драматическое не происходит, поэтапный новый механизм работает очень хорошо. Старайтесь не менять свой алгоритм так часто, что у вас есть три или более на ходу сразу - хотя нет никаких технических причин, по которым эта схема не может справиться. Также попробуйте создать свою базу данных так, чтобы размеры хэша могли расти без возникновения ошибок (так что позволить расширять пространство от 64 до 128 байт или от 128 до 256 или...).
Ответ 2
Да, соль есть только для предотвращения радужных атак на хешированные пароли. Обычно я использую одно значение соли для всех паролей. Он хранится в моем исходном коде или конфигурации, поэтому он не находится в базе данных. Но, вероятно, лучше использовать другую соль для каждого пользователя. Таким образом, два пользователя с одинаковым паролем не получат одинаковый хэш.
Вы можете просто сохранить соль в базе данных вместе с паролем. Цель соли заключается в том, что вы не можете прекомпретировать радужный стол. Это займет слишком много времени. Больше времени, чем просто грубый ввод пароля. Даже если соль известна, должны быть созданы полные радужные столы для этой соли, которые чрезвычайно дороги. Таким образом, это не имеет большого значения, если соль известна.
Неважно, как вы выбираете соль, пока вы убедитесь, что она достаточно длинная. Согласно Википедии, 12-битный хеш (используемый старыми паролями unix) чрезвычайно дорог, чтобы победить, но возможно. 128-бит (как используется, например, MD5) слишком дорого для defeaut в обозримом будущем.
Смотрите также: http://en.wikipedia.org/wiki/Rainbow_table#Defense_against_rainbow_tables
Ответ 3
Соли не являются секретом. Их можно хранить в ясном виде вместе с хэшированной солью + пароль. Хеши соленые, чтобы избежать атак со словарями. Оба правильных варианта - соление со случайным значением, хранящимся вместе с паролем, или хэширование имени пользователя вместе с паролем. Тем не менее, я бы рекомендовал очень специфическую схему хэша, а именно HTTP Дайджест HA1 хеш: user_name : realm : password
. Это дает дополнительное преимущество, чтобы иметь возможность аутентифицировать вызовы HTTP Digest, которые будут использоваться для автоматического доступа, например, API-интерфейс REST для вашего сайта.
Прежде чем перейти к осуждению использования MD5 вместо SHA1 (в соответствии с требованиями хэш-схемы HTTP-дайджеста), но предоставление по запросу MD5-хеш-коллизии для схемы Digest все еще далеки от действия в обозримом будущем и дополнительным преимуществом автоматического доступа (думаю, WebRequest, curl и т.д.) не следует пренебрегать.