Какой тип столбца / длину следует использовать для хранения хешированного пароля Bcrypt в базе данных?
Я хочу сохранить хешированный пароль (используя BCrypt) в базе данных. Что будет хорошим типом для этого, и какой будет правильная длина? Пароли, хэшированные с BCrypt, всегда имеют одинаковую длину?
РЕДАКТИРОВАТЬ
Пример хэша:
$2a$10$KssILxWNR6k62B7yiX0GAe2Q7wwHlrzhF3LqtVvpyvHZf0MwvNfVu
Кажется, что после хеширования некоторых паролей BCrypt всегда генерирует 60-ти символьные хэши.
РЕДАКТИРОВАТЬ 2
Извините, что не упомянул реализацию. Я использую jBCrypt.
5 ответов
Модульный формат склепа для bcrypt состоит из
$2$
,$2a$
или же$2y$
определение алгоритма и формата хэширования- двухзначное значение, обозначающее параметр стоимости, за которым следует
$
- 53 символа в кодировке base-64 длиной (они используют алфавит
.
,/
,0
-9
,A
-Z
,a
-z
отличается от стандартного алфавита кодирования Base 64), состоящего из:- 22 символа соли (фактически только 128 бит из 132 декодированных бит)
- 31 символ зашифрованного вывода (фактически только 184 бита из 186 декодированных бит)
Таким образом, общая длина составляет 59 или 60 байтов соответственно.
При использовании формата 2a вам понадобится 60 байтов. И поэтому для MySQL я рекомендую использовать CHAR(60) BINARY
или же BINARY(60)
(см . _bin и двоичные сопоставления для получения информации о разнице).
CHAR
не является бинарно-безопасным, и равенство зависит не только от значения байта, но и от фактического сопоставления; в худшем случае A
рассматривается как равный a
, Увидеть _bin
а также binary
Сборники для получения дополнительной информации.
Хеш Bcrypt может храниться в BINARY(40)
колонка.
BINARY(60)
Как показывают другие ответы, это самый простой и естественный выбор, но если вы хотите максимизировать эффективность хранения, вы можете сэкономить 20 байтов, без потерь деконструируя хеш. Я подробно описал это на GitHub: https://github.com/ademarre/binary-mcf
Хеши Bcrypt следуют структуре, называемой модульным форматом шифрования (MCF). Binary MCF (BMCF) декодирует эти текстовые хэш-представления в более компактную двоичную структуру. В случае Bcrypt результирующий двоичный хэш составляет 40 байтов.
Гамбо хорошо объяснил четыре компонента хеша Bcrypt MCF:
$<id>$<cost>$<salt><digest>
Декодирование в BMCF происходит так:
$<id>$
может быть представлен в 3 битах.<cost>$
, 04-31, могут быть представлены в 5 битах. Положите их вместе на 1 байт.- Соль из 22 символов представляет собой (нестандартное) представление base-64 из 128 битов. Декодирование Base-64 дает 16 байтов.
- Дайджест хеша из 31 символа может быть декодирован в формате base-64 до 23 байтов.
- Соберите все вместе для 40 байтов:
1 + 16 + 23
Вы можете прочитать больше по ссылке выше, или изучить мою реализацию PHP, также на GitHub.
Если вы используете PHP password_hash()
с PASSWORD_DEFAULT
Алгоритм генерации хеша bcrypt (который, как я полагаю, представляет большой процент людей, читающих этот вопрос), обязательно следует учитывать, что в будущем password_hash()
может использовать другой алгоритм по умолчанию, и это может повлиять на длину хэша (но он не обязательно будет длиннее).
Со страницы руководства:
Обратите внимание, что эта константа предназначена для изменения со временем, так как в PHP добавляются новые и более сильные алгоритмы. По этой причине длина результата от использования этого идентификатора может меняться со временем. Поэтому рекомендуется сохранять результат в столбце базы данных, который может расширяться за пределы 60 символов (255 символов будет хорошим выбором).
Использование bcrypt, даже если у вас есть 1 миллиард пользователей (то есть, вы в настоящее время конкурируете с Facebook) для хранения 255-байтовых хэшей паролей, это будет всего ~255 ГБ данных - размером с небольшой жесткий диск SSD. Крайне маловероятно, что хранение хэша пароля станет узким местом в вашем приложении. Однако, если вы по какой-то причине нехватите места для хранения, вы можете использовать PASSWORD_BCRYPT
заставить password_hash()
использовать bcrypt, даже если это не по умолчанию. Просто будьте в курсе всех уязвимостей, обнаруженных в bcrypt, и просматривайте примечания к выпуску каждый раз, когда выходит новая версия PHP. Если алгоритм по умолчанию когда-либо изменяется, было бы хорошо проанализировать причину и принять обоснованное решение, использовать новый алгоритм или нет.
Я не думаю, что есть какие-то хитрые уловки, которые вы можете сделать, храня это, как вы можете сделать, например, с хешем MD5.
Я думаю, что лучше всего хранить его как CHAR(60)
как всегда 60 символов
Я думаю, что лучший выбор - небинарный тип, потому что по сравнению с ним меньше комбинаций и он должен быть быстрее. Если данные закодированы с помощью base64_encode, то каждая позиция, каждый байт имеют только 64 возможных значения. При кодировании с помощью bin2hex каждый байт имеет только 16 возможных значений, но строка намного длиннее. В двоичном байте по 256 позиций на каждый. Я использую для хэшей в виде столбца encode64 VARCHAR(255) с набором символов ascii и тем же сопоставлением. VARBINARY вызывает проблему сравнения, как описано в документации MySQL. Я не знаю, почему ответы на советы по использованию VARBINARY имеют так много положительных сторон. Я проверил это на своем авторском сайте, где измеряю время (просто обновите, чтобы увидеть).