Как bcrypt может иметь встроенные соли?
В статье Coda Hale "Как безопасно хранить пароль" утверждается, что:
В bcrypt есть встроенные соли, чтобы предотвратить атаки радужного стола.
Он цитирует эту статью, в которой говорится, что в реализации OpenBSD bcrypt
:
OpenBSD генерирует 128-битную соль bcrypt из ключевого потока arcfour (arc4random(3)), заполненного случайными данными, которые ядро собирает по времени устройства.
Я не понимаю, как это может работать. В моей концепции соли:
- Он должен быть разным для каждого сохраненного пароля, поэтому для каждого из них необходимо создать отдельную радужную таблицу.
- Он должен быть где-то сохранен, чтобы его можно было повторять: когда пользователь пытается войти в систему, мы предпринимаем попытку ввода пароля, повторяем ту же процедуру с использованием соли и хэша, которую мы делали при первоначальном сохранении его пароля, и сравниваем
Когда я использую Devise (менеджер входа в Rails) с bcrypt, в базе данных нет столбца соли, поэтому я запутался. Если соль случайная и нигде не хранится, как мы можем надежно повторить процесс хеширования?
Короче говоря, как bcrypt может иметь встроенные соли?
6 ответов
Это bcrypt:
Генерация случайной соли. Коэффициент стоимости был предварительно настроен. Собери пароль.
Получите ключ шифрования из пароля, используя соль и коэффициент стоимости. Используйте его для шифрования известной строки. Сохраните стоимость, соль и зашифрованный текст. Поскольку эти три элемента имеют известную длину, их легко объединить и сохранить в одном поле, но позже можно будет разбить их на части.
Когда кто-то пытается аутентифицироваться, извлекайте сохраненную стоимость и соль. Получите ключ от ввода пароля, стоимости и соли. Зашифруйте ту же самую известную строку. Если сгенерированный зашифрованный текст совпадает с сохраненным зашифрованным текстом, пароль совпадает.
Bcrypt работает очень похоже на более традиционные схемы, основанные на таких алгоритмах, как PBKDF2. Основным отличием является использование производного ключа для шифрования известного простого текста; другие схемы (разумно) предполагают, что функция вывода ключа необратима, и сохраняют полученный ключ напрямую.
Хранится в базе данных, bcrypt
"hash" может выглядеть примерно так:
$ 2a $ 10 $ vI8aWBnW3fID.ZQ4 / zo1G.q1lRps.9cGLcZEiGDMVr5yUP1KUOYTa
На самом деле это три поля, разделенные символом "$":
2a
идентифицируетbcrypt
версия алгоритма, которая была использована.10
фактор стоимости; 210 10 итераций функции получения ключа (кстати, этого недостаточно. Я бы рекомендовал стоимость 12 или более).vI8aWBnW3fID.ZQ4/zo1G.q1lRps.9cGLcZEiGDMVr5yUP1KUOYTa
это соль и зашифрованный текст, объединенный и закодированный в модифицированной Base-64. Первые 22 символа декодируются до 16-байтового значения для соли. Остальные символы - это зашифрованный текст, который нужно сравнить для аутентификации.
Этот пример взят из документации по реализации Ruby в Coda Hale.
Я считаю, что эту фразу следовало бы сформулировать следующим образом:
bcrypt содержит соли, встроенные в сгенерированные хэши, чтобы предотвратить атаки радужных таблиц.
bcrypt
Сама утилита, похоже, не ведет список солей. Скорее, соли генерируются случайным образом и добавляются к выходным данным функции, чтобы их потом запомнили (в соответствии с реализацией Javabcrypt
). Другими словами, "хэш", сгенерированный bcrypt
это не просто хэш. Скорее, это хеш и соль сцепленные.
Это простые термины ...
Bcrypt не имеет базы данных, в которой хранится соль ...
Соль добавляется в хеш в формате base64 ....
Вопрос в том, как bcrypt проверяет пароль, когда у него нет базы данных ...?
Что делает bcrypt, так это то, что он извлекает соль из хеша пароля ... Используйте извлеченную соль для шифрования простого пароля и сравнивает новый хеш со старым, чтобы увидеть, совпадают ли они ...
Чтобы было понятнее,
Направление регистрации / входа ->
Пароль + соль зашифровывается с помощью ключа, созданного из: стоимости, соли и пароля. мы называем это зашифрованное значениеcipher text
. затем мы добавляем соль к этому значению и кодируем его с помощью base64. прикрепив к нему стоимость, и это полученная строка изbcrypt
:
$2a$COST$BASE64
Это значение со временем сохраняется.
Что нужно сделать злоумышленнику, чтобы найти пароль? (другое направление <-)
В случае, если злоумышленник получил контроль над БД, злоумышленник легко расшифрует значение base64, и тогда он сможет увидеть соль. соль не секрет. хотя это случайно. Затем ему нужно будет расшифроватьcipher text
.
Что важнее: в этом процессе нет хеширования, достаточно дорогостоящее шифрование - дешифрование. таким образом, радужные таблицы здесь менее актуальны.
Представим себе таблицу с 1 хешированным паролем. Если хакер получит доступ, он будет знать соль, но ему придется рассчитывать большой список для всех общих паролей и сравнивать после каждого расчета. Это займет время, и он взломал бы только 1 пароль.
Представьте себе второй хешированный пароль в той же таблице. Соль видна, но тот же расчет, приведенный выше, должен повториться, чтобы взломать и эту, потому что соли разные.
Если бы не использовались случайные соли, было бы намного проще, почему? Если мы используем простое хеширование, мы можем просто сгенерировать хеши для общих паролей 1 раз (радужная таблица) и просто выполнить простой поиск по таблице или простой поиск файлов между хешами таблицы db и нашими предварительно рассчитанными хешами, чтобы найти простые пароли.
Это из документации по интерфейсу PasswordEncoder от Spring Security,
* @param rawPassword the raw password to encode and match
* @param encodedPassword the encoded password from storage to compare with
* @return true if the raw password, after encoding, matches the encoded password from
* storage
*/
boolean matches(CharSequence rawPassword, String encodedPassword);
Это означает, что нужно сопоставить rawPassword, который пользователь введет снова при следующем входе в систему, и сопоставить его с зашифрованным паролем Bcrypt, который хранится в базе данных во время предыдущего входа в систему / регистрации.