Ответ 1
Новая соль должна генерироваться случайным образом для каждого пользователя и каждый раз, когда они сменяют свой пароль как минимум. Не просто полагайтесь, например, на соль соломы, поскольку это, в первую очередь, наносит ущерб использованию соли.
Использование уникальной соли для каждого пользователя заключается в том, что если у двух пользователей одинаковый пароль, они не получат одинаковый результирующий хеш. Это также означает, что атака грубой силы должна монтироваться против каждого пользователя отдельно, а затем быть в состоянии предварительно вычислить таблицу радуги для сайта.
Затем вы сохраняете результат хэширования соли и пароля в базе данных hash(salt + password)
вместе с salt
для каждого пользователя. Вы можете хранить их в отдельных столбцах или все в одном столбце (разделенные символом, который не используется в хэшах, поэтому ;
). Пока вы можете получить оба, все будет хорошо.
Однако, если ваша база данных скомпрометирована, либо из-за того, что кто-то получает локальный доступ, либо через атаки SQL-инъекций, тогда будет доступен как соль, так и конечный хеш, что означает, что атака грубой силы на пароли пользователей будет тривиальной. Чтобы бороться с этим, как предложено The Rook, вы также можете использовать секретный ключ sitewide, хранящийся в файле локально, в качестве другого ввода вашего метода хэширования, чтобы также понадобился злоумышленник чтобы знать это, чтобы установить эффективную атаку. Это означает, что ваша БД должна быть скомпрометирована, и злоумышленнику потребуется доступ к локальным файлам. Поэтому используйте hash(hash(salt + secret) + password)
и т.д.
В то время как в большинстве алгоритмов вы стремитесь сделать все как можно быстрее, для хэширования паролей вы хотите замедлить его, это называется Укрепление ключа (или иногда Key Stretching). Если для возврата хеш-функции требуется 0,00001 секунд, кто-то может попытаться перевести более 100 000 паролей в секунду, пока не найдет совпадение. Если для вашей хеш-функции требуется 1 секунда, чтобы вывести результат, это не очень важно, если кто-то входит в ваше приложение, но для взлома пароля это большая сделка, так как каждая попытка теперь займет 1 секунду, чтобы получить результат, то есть потребовалось бы в 100 000 раз больше времени, чтобы протестировать каждый принудительный пароль, который будет использоваться с вашей исходной хеш-функцией.
Чтобы сделать вашу функцию хеширования более медленной, вам просто нужно запустить ее несколько раз. Например, вы можете сделать new_hash = salt + password + previous_hash
100 000 раз. Возможно, вам потребуется настроить количество итераций на более высокое значение, если оно слишком быстрое. Если вы хотите изменить значение позже, обязательно сохраните количество итераций с записью пользователя, чтобы вы не влияли на сохраненные ранее пароли.
В вашей записи пользователя теперь должно быть поле, отформатированное примерно так: "$<algorithm>$<iterations>$<salt>$<hash>
" (или как отдельные поля, если вы хотите).
Когда пользователь вводит свой пароль, вы можете получить соль и количество итераций из БД и секретной таблицы из локального файла и подтвердить, что при запуске одинакового количества итераций с солью и паролем результат хэш соответствует тому, что вы сохранили.
Если пользователь меняет свой пароль, вы должны создать новую соль.
Используемый метод хэширования не имеет значения (но алгоритм хэширования *). Выше я предложил hash(hash(salt + secret) + password)
, но в равной степени это могло быть hash(hash(salt) + hash(secret) + hash(password))
. Метод, который вы используете, не изменяет эффективность вашего хранилища паролей, на самом деле он не более безопасен, чем другой. Опираясь на дизайн того, как вы храните пароль и соль вместе для обеспечения безопасности, называется безопасность через неизвестность, и этого следует избегать.
* Вы не должны использовать MD5 или SHA-1, поскольку они считаются небезопасными. Вместо этого используйте семейство SHA-2 (SHA256, SHA512 и т.д.). (Ссылка)