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

213

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

ИЗМЕНИТЬ

Пример хеша:

$2a$10$KssILxWNR6k62B7yiX0GAe2Q7wwHlrzhF3LqtVvpyvHZf0MwvNfVu

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

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

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

  • 0
    Также см. Фреймворк для хэширования паролей в PHP в PHP . Его портативный и защищенный от ряда распространенных атак на пароли пользователей. Парень, который написал фреймворк (SolarDesigner), тот же, кто написал Джона Потрошителя и является судьей в конкурсе хэширования паролей . Таким образом, он знает кое-что о атаках на пароли.
  • 1
    Если кто-то падает на это в поисках решения для scrypt : ответ Гамбо также относится к scrypt. Я лично применил BINARY (64) в MySQL, и это позволило мне позже проверить на равенство байтов в Python.
Теги:
types
hash
bcrypt
storage

4 ответа

272
Лучший ответ

Формат модульного склепа для bcrypt состоит из

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

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

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

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

  • 26
    Имейте в виду - сохранение в двоичном виде (60) может привести к неожиданному поведению для равенства строк (среди прочего). В .NET это может быть преодолено с помощью String.Equals (fromDataBaseBinary60string, typicalStString, StringComparison.InvariantCulture)
  • 7
    Если вы определите столбец как CHAR (60) CHARACTER SET latin1 COLLATE latin1_bin, теперь вы получите преимущества точного сравнения строк без использования двоичного столбца.
Показать ещё 7 комментариев
38

Атрибут Bcrypt может храниться в столбце BINARY(40).

BINARY(60), как показывают другие ответы, является самым простым и естественным выбором, но если вы хотите максимизировать эффективность хранения, вы можете сэкономить 20 байтов без потерь, деконструируя хэш. Я подробно описал это на GitHub: https://github.com/ademarre/binary-mcf

Хэши Bcrypt следуют структуре, называемой модульным склепом (MCF). Двоичный MCF (BMCF) декодирует эти текстовые представления хеширования в более компактную двоичную структуру. В случае Bcrypt результирующий двоичный хэш составляет 40 байт.

Gumbo отлично справился с объяснением четырех компонентов хэша MCC Bcrypt:

$<id>$<cost>$<salt><digest>

Декодирование в BMCF происходит следующим образом:

  • $<id>$ может быть представлен в 3 битах.
  • <cost>$, 04-31, может быть представлена ​​в 5 бит. Поместите их вместе для 1 байт.
  • 22-символьная соль представляет собой (нестандартное) представление base-64 из 128 бит. Базовое 64-битное кодирование дает 16 байт.
  • 31-символьный хэш-дайджест может быть декодирован в base-64 до 23 байтов.
  • Объедините все это в 40 байт: 1 + 16 + 23

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

  • 31
    Стоимость более длинного поля: 20 байт, умноженных на миллион + записей: 20 МБ, как только вы достигнете миллиона записей +. Стоимость неправильной реализации сокращенной длины поля в очень сложной области безопасности и проектирования: $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ $$$$$$$$$$$$$$$$$$$$$$$$$$$ Вы занимаетесь математикой.
  • 5
    @Kzqai, как я уже сказал, больший 60-байтовый столбец является наиболее естественным выбором, но насколько агрессивно стремиться к эффективности хранения зависит от проекта. Например, принято пытаться разместить всю базу данных в памяти, и 20 МБ здесь и еще 20 там могут быстро сложиться в среде с ограниченным объемом памяти.
Показать ещё 3 комментария
16

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

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

  • 0
    Хотя в документации PHP отмечается, что столбцы должны содержать больше данных для будущих выпусков ...
  • 12
    Нет причин для золотой тарелки. Если используемому программному обеспечению требуется шестьдесят байтов, выделите шестьдесят байтов. Если в вашем программном обеспечении есть будущая версия, которая изменит это, вы можете беспокоиться об этом, когда эта версия произойдет. Вы не должны автоматически устанавливать обновления, изменяющие функциональность.
15

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

На странице руководства:

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

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню