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


317

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

EDIT

Приклад хешу:

$2a$10$KssILxWNR6k62B7yiX0GAe2Q7wwHlrzhF3LqtVvpyvHZf0MwvNfVu

Після хешування деяких паролів, здається, що BCrypt завжди генерує 60 хешів символів.

EDIT 2

Вибачте, що не згадуєте про реалізацію. Я використовую jBCrypt .


Також дивіться рамку хешування паролів PHP Openwall (PHPass). Його портативний та загартований проти низки поширених атак на паролі користувачів. Хлопець, який написав рамки (SolarDesigner) - той самий хлопець, який написав Джона The Ripper і сидить як суддя у змаганнях з пароля . Тож він знає річ чи дві про атаки на паролі.
— jww

1
Якщо хтось потрапляє на це, шукаючи рішення для скрипту : відповідь Gumbo також стосується scrypt. Я особисто застосував BINARY (64) в MySQL, і це дозволило мені перевірити рівність байтів під Python пізніше.
— Філіп Геберт

Відповіді:


368

Модульний формат крипт для 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) ( для інформації про різницю див . _Bin та бінарні Collations ).

CHARне є бінарним безпечним і рівність не залежить тільки від байтового значення, але і від фактичного зіставлення; в гіршому випадку Aтрактується як рівний a. Див і Collations для отримання додаткової інформації._binbinary


28
Будьте в курсі - зберігання як бінарного (60) може спричинити несподівану поведінку для рівності рядків (серед іншого). У .NET це можна подолати, використовуючи String.Equals (відDataBaseBinary60string, typishString, StringComppare.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 з правильним порівнянням), ви не ризикуєте десь іншим чином змінити налаштування, що робить його порівняльним з урахуванням регістру. Це також робить ваш намір більш зрозумілим, що, як правило, добре - ви зберігаєте бінарні дані; ви повинні зберігати його як двійкові дані.
— Фонд позову Моніки

51

Хеш-код Bcrypt може зберігатися у BINARY(40)стовпці.

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

Хеши криптовалют слідують за структурою, що називається модульним форматом крипт (MCF). Двійкові MCF (BMCF) декодує ці текстові хеш-подання до більш компактної бінарної структури. У випадку Bcrypt отриманий бінарний хеш становить 40 байт.

Gumbo зробив гарну роботу, пояснивши чотири компоненти хеша Bcrypt MCF:

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

Розшифровка до BMCF відбувається так:

  1. $<id>$ може бути представлений у 3 бітах.
  2. <cost>$, 04-31, можна представити у 5 бітах. Складіть їх разом на 1 байт.
  3. Сіль з 22 символами є (нестандартним) базовим 64-представленням 128 біт. Розшифровка Base-64 дає 16 байт.
  4. 31-символьний хеш-дайджест може бути базовим - 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
— Naveen Kumar 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 зазначається, що стовпці повинні мати можливість зберігати більше даних для майбутніх випусків ...
— Julian F. Weinert

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