Какой тип столбца / длину следует использовать для хранения хешированного пароля Bcrypt в базе данных?


318

Я хочу сохранить хешированный пароль (используя BCrypt) в базе данных. Что будет хорошим типом для этого, и какой будет правильная длина? Пароли, хэшированные с BCrypt, всегда имеют одинаковую длину?

РЕДАКТИРОВАТЬ

Пример хэша:

$2a$10$KssILxWNR6k62B7yiX0GAe2Q7wwHlrzhF3LqtVvpyvHZf0MwvNfVu

Похоже, что после хеширования некоторых паролей BCrypt всегда генерирует хэши по 60 символов.

РЕДАКТИРОВАТЬ 2

Извините, что не упомянул реализацию. Я использую jBCrypt .


Также см. Фреймворк хеширования паролей в PHP для PHP . Его портативный и защищенный от ряда распространенных атак на пароли пользователей. Парень, который написал фреймворк (SolarDesigner), тот же, кто написал Джона Потрошителя и является судьей в конкурсе хэширования паролей . Таким образом, он знает кое-что о атаках на пароли.
— jww

1
Если кто-то падает на это в поисках решения для scrypt : ответ Гамбо также относится к scrypt. Я лично применил BINARY (64) в MySQL, и это позволило мне позже проверить на равенство байтов в Python.
— Филипп Хеберт

Ответы:


370

Модульный формат склепа для bcrypt состоит из

  • $2$, $2a$Или $2y$идентификации алгоритма хеширования и формат
  • двухзначное значение, обозначающее параметр стоимости, за которым следует $
  • 53 символов базового 64-кодированное значение (они используют алфавит ., /, 0- 9, A- Z, a- , zчто отличается от стандартной базы 64 кодирования алфавита) , состоящий из:
    • 22 символа соли (фактически только 128 бит из 132 декодированных бит)
    • 31 символ зашифрованного вывода (фактически только 184 бита из 186 декодированных бит)

Таким образом, общая длина составляет 59 или 60 байтов соответственно.

При использовании формата 2a вам понадобится 60 байтов. И , таким образом , для MySQL я рекомендую использовать CHAR(60) BINARYилиBINARY(60) (см The _bin и бинарные Collations для получения информации о различиях).

CHARне является бинарно-безопасным, и равенство зависит не только от значения байта, но и от фактического сопоставления; в худшем случае Aрассматривается как равный a. См . _binИ binaryсопоставления для получения дополнительной информации.


28
Имейте в виду - сохранение в двоичном виде (60) может вызвать неожиданное поведение для равенства строк (среди прочего). В .NET это можно преодолеть с помощью String.Equals (fromDataBaseBinary60string, typicalStString, StringComparison.InvariantCulture)
— JHubbard80,

8
Если вы определите столбец как CHAR (60) CHARACTER SET latin1 COLLATE latin1_bin, теперь вы получите преимущества точного сравнения строк без использования двоичного столбца.
— Бен

2
@AndreFigueiredo SQL_Latin1_General_CP1_CS_ASнеизвестен в MySQL. Что известно latin1_general_cs.
— Гамбо

1
Я хотел бы иметь определение здесь для того, что 2, 2aи 2yсреднего значения для алгоритма хеширования и формата. Я не мог найти простой ответ с некоторыми поисками.
— jocull

2
@Neon Проблема в том, что вы можете сравнивать разные хеши, чтобы они были равны. Если вы явно укажете, что это двоичный столбец (или VARCHAR с правильным сопоставлением), вы не рискуете где-то еще изменить какой-либо параметр, который делает сравнение без учета регистра. Это также делает ваши намерения более ясными, что, как правило, хорошо - вы храните двоичные данные; Вы должны хранить его как двоичные данные.
— Фонд Моника иск

52

Хеш 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 происходит так:

  1. $<id>$ может быть представлен в 3 битах.
  2. <cost>$, 04-31, могут быть представлены в 5 битах. Положите их вместе на 1 байт.
  3. Соль из 22 символов представляет собой (нестандартное) представление base-64 из 128 битов. Декодирование Base-64 дает 16 байтов.
  4. 31-символьный хэш-дайджест может быть декодирован в формате base-64 до 23 байтов.
  5. Соберите все вместе для 40 байтов: 1 + 16 + 23

Вы можете прочитать больше по ссылке выше, или изучить мою реализацию PHP , также на GitHub.


49
Стоимость более длинного поля: 20 байт, умноженных на миллион + записей: 20 МБ, как только вы достигнете миллиона записей. Стоимость неправильной реализации укороченной длины поля в очень сложной области безопасности и проектирования: $$$$$$$$$$$$$$$$$$$$$$$$$$$ Вы занимаетесь математикой.
— Kzqai

6
@Kzqai, как я уже сказал, больший 60-байтовый столбец является наиболее естественным выбором, но насколько агрессивно стремиться к эффективности хранения зависит от проекта. Например, принято пытаться разместить всю базу данных в памяти, и 20 МБ здесь и еще 20 там могут быстро сложиться в среде с ограниченным объемом памяти.
— Андре Д

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

11
@Kzqai Здесь нет риска ослабить безопасность вашей библиотеки Bcrypt. Это кодировка данных, которая отменяется при извлечении из хранилища до проверки пароля. Это не территория "не катите свою крипто".
— Андре Д

1
Хорошее объяснение. :) Хотя ваше объяснение дало отличную идею, я просто хочу использовать 60 символов, даже 100 символов, просто чтобы быть в безопасности. Хорошие дебаты также @Kzqai и AndreD
— Навин Кумар V

23

Если вы используете PHP password_hash()с PASSWORD_DEFAULTалгоритмом для генерации хэша bcrypt (который, как я полагаю, представляет большой процент людей, читающих этот вопрос), не забывайте, что в будущем password_hash()может использоваться другой алгоритм по умолчанию, и поэтому влияет на длину хеша (но она не обязательно может быть длиннее).

Со страницы руководства:

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

Использование bcrypt, даже если у вас есть 1 миллиард пользователей (то есть вы в настоящее время конкурируете с Facebook) для хранения 255-байтовых хэшей паролей, это будет всего ~ 255 ГБ данных - размером с небольшой жесткий диск SSD. Крайне маловероятно, что хранение хэша пароля станет узким местом в вашем приложении. Однако в шансе , что пространство для хранения действительно является проблемой для какой - то причины, вы можете использовать PASSWORD_BCRYPTв силу password_hash()для использования Bcrypt, даже если это не по умолчанию. Просто будьте в курсе всех уязвимостей, обнаруженных в bcrypt, и просматривайте примечания к выпуску каждый раз, когда выходит новая версия PHP. Если алгоритм по умолчанию когда-либо изменяется, было бы хорошо проанализировать причину и принять обоснованное решение, использовать новый алгоритм или нет.


20

Я не думаю, что есть какие-то хитрые уловки, которые вы можете сделать, храня это, как вы можете сделать, например, с хешем MD5.

Я думаю, что ваш лучший выбор - хранить его как CHAR(60)всегда длиной 60 символов


Хотя в документации PHP отмечается, что столбцы должны содержать больше данных, для будущих выпусков ...
— Джулиан Ф. Вейнерт,

16
Нет причин для золотой тарелки. Если используемому программному обеспечению требуется шестьдесят байтов, выделите шестьдесят байтов. Если в вашем программном обеспечении есть будущая версия, которая изменит это, вы можете беспокоиться об этом, когда эта версия произойдет. Вы не должны автоматически устанавливать обновления, изменяющие функциональность.
— Тайлер Кромптон
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.