Какой тип столбца / длину следует использовать для хранения хешированного пароля 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.