Безопаснее ли хешировать пароль несколько раз?

43

Я несколько раз читал, что при хранении паролей рекомендуется использовать двойное хеширование строк (например, с md5, затем с sha1, очевидно, с солями).

Я предполагаю, что первый вопрос, "действительно ли это правильно?" Если нет, то, пожалуйста, отклоните остальную часть этого вопроса :)

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

Позвольте мне сказать по-другому: у нас есть x количество строк, которые при хешировании уменьшаются до y возможных строк. То есть столкновения в первом сете. Теперь, переходя от второго к третьему набору, возможно ли, чтобы происходило одно и то же (т. Е. Коллизии в наборе всех возможных строк 'y', которые приводят к тому же хешу в третьем наборе)?

В моей голове все, что я вижу, это «воронка» для каждого вызова хэш-функции, «вливание» бесконечного набора возможностей в конечный набор и так далее, но, очевидно, каждый вызов работает над конечным набором перед ним, давая нам установить не больше, чем вход.

Может быть, пример объяснит мои разговоры? Возьмем 'hash_function_a', который даст 'a' и 'b' хэш '1', и даст 'c' и 'd' хэш '2'. Используя эту функцию для хранения паролей, даже если пароль «а», я мог бы использовать пароль «б».

Возьмем 'hash_function_b', который даст '1' и '2' хэш '3'. Если бы я использовал его как «вторичный хеш» после «hash_function_a», то даже если пароль «a», я мог бы использовать «b», «c» или «d».

Вдобавок ко всему, я понимаю, что соли должны использоваться, но они не меняют тот факт, что каждый раз, когда мы отображаем «x» входы на «меньше чем x» выходы. Я не думаю

Может кто-нибудь объяснить мне, что мне здесь не хватает?

Благодарность!

РЕДАКТИРОВАТЬ: для чего это стоит, я не делаю это сам, я использую bcrypt. И меня не очень беспокоит, полезно ли это для «использования циклов» для «хакера». Мне искренне просто интересно, снижает ли этот процесс «безопасность» с точки зрения коллизионного хэша.

нарцисс
источник
2
@ S.Lott: Я действительно не понимаю, как это отвечает на фактический вопрос, хотя ... все, что он говорит, это либо "не делай это сам, используй это", либо "это хорошо, чтобы занимать время!". .. ни один из которых не отвечает "это на самом деле более безопасно". Опять же, если я что-то упустил.
Нарцисс
@MetalMikester: Да, это была вчерашняя статья: thedailywtf.com/Articles/Bulletproof-Encryption.aspx
FrustratedWithFormsDesigner
Это не относится к теме информационной безопасности, но выглядит как хорошее совпадение для криптографии. На самом деле это выглядит очень похоже на этот вопрос .
Я знаю компанию, которая хотела использовать несоленую MD5(password). Мы сказали, что это небезопасно, поэтому они предложили MD5(MD5(password))вместо этого использовать ...
конфигуратор
Принятый ответ не является правильным ответом!
Маркус

Ответы:

27

Это больше подходит для security.stackexchange, но ...

Проблема с

hash1(hash2(hash3(...hashn(pass+salt)+salt)+salt)...)+salt)

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

Более сильная цепь будет

hash1(hash2(hash3(...hashn(pass + salt) + pass + salt) + pass + salt)...) + pass + salt)

Здесь мы избегаем проблемы ранних коллизий и по сути генерируем соль, которая зависит от пароля для окончательного хэша.

И если один шаг в цепочке сталкивается, это не имеет значения, потому что на следующем шаге пароль используется снова и должен дать другой результат для разных паролей.

чокнутый урод
источник
Итак, сейчас я вижу, что добавление «пароль + соль» в качестве соли к следующему раунду хеширования может увеличить количество «вещей», которые могут попасть в воронку, теперь я просто должен понять, «сколько». Спасибо.
Нарцисс
На самом деле, я думаю, что я понял это сейчас: принудительно вводя пароль в каждый уровень хэширования, он фактически сокращает количество возможных коллизий, по сути требуя, чтобы «конфликтующий пароль» и реальный пароль имели соответствующие хэши для каждого «вызова» , правильно? Я думаю, что мне не хватало части «поставить пароль на каждом слое»! Еще раз спасибо.
Нарцисс
@Narcissus не проблема, и у этого также есть бонус, позволяющий использовать более слабые внутренние хеши (если внешние / финальные хэши сильны), поскольку внутренние хеши только генерируют соль для следующего прохода
урод с трещоткой
Хм, я думаю, что проблема немного больше (и глубже), чем это. С помощью радужных атак вы можете просто создавать таблицы с учетом всех ваших хэшей, и проблема остается.
woliveirajr
4
@ Нарцисс: в очень коротком ответе: Да, это не более безопасно. Да, возможно, это еще менее безопасно.
woliveirajr
54

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

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

Последние алгоритмы хеширования, такие как bcrypt, основаны на этой идее; они содержат параметр для управления вычислительной сложностью хэша, так что вы можете масштабировать его по мере того, как аппаратное ускорение прогрессирует: когда аппаратное обеспечение становится быстрее в два раза, вы увеличиваете сложность, чтобы компенсировать, таким образом, время, необходимое для грубой силы вашего хэши остаются примерно постоянными.

tdammers
источник
2
Это правильный ответ!
Маркус
@ markus: согласно обсуждению, которое я прочитал, это правильно только из-за добавления «и хорошей соли», на которое ссылается принятый ответ, не так ли? Почему этот правильный, а принятый ответ - нет?
Нарцисс
Это правильный ответ, потому что единственная причина применения одной и той же хэш-функции несколько раз (параметризованная) заключается в том, что вы можете использовать эту итерацию для настройки более быстрого оборудования. В противном случае многократное хеширование не приносит пользы.
Маркус
@ Нарцисс Ключевым моментом здесь является энтропия. Существует различие между многократным хэшированием, использующим один и тот же метод, и многократным хешированием, использующим разные методы.
Сакиск
3

Не пытайтесь написать свою собственную схему хеширования паролей, если вы не хотите пройти курс криптографии и / или проектирования безопасности.

Вы должны использовать хорошо зарекомендовавшую себя реализацию хеширования паролей, которая, в свою очередь, должна использовать функцию вывода ключей ( KDF ), такую ​​как PBKDF2, bcrypt, scrypt или более новый Argon2.

Хорошие KDF включают в себя фактор работы, обычно несколько итераций, чтобы увеличить стоимость атак в автономном режиме. Можно сказать, что эти KDF хэшируют пароль несколько раз, используя один и тот же алгоритм каждый раз. Нет смысла использовать алгоритм дайджеста нескольких сообщений, на что указывают другие.

Эрван Легран
источник
1
ссылка https://crackstation.net/hashing-security.htm заблокирована брандмауэром
комат
1
@gnat По какой-то причине я пропустил ваш комментарий относительно заблокированного URL. Я заменил его ссылкой на википедию.
Эрван Легран
2

В общем случае вам не нужно использовать более одного алгоритма хеширования.

Что вам нужно сделать, это:

Используйте соль: соль используется не только для того, чтобы сделать ваш пароль более безопасным , она используется для предотвращения атаки на радужный стол. Таким образом, кому-то придется потрудиться, пытаясь предварительно вычислить хэш для паролей, которые вы храните в своей системе.

Используйте несколько взаимодействий: вместо просто SHA (пароль + соль), сделайте SHA (SHA (SHA (SHA (SHA (... SHA (пароль + соль)))))). Или представить по-другому:

hash = sha(password + salt)
for i=1 , i=5000, i++ {
    hash = sha(hash + salt);
}

И, наконец, выберите хорошую функцию хеширования. SHA, MD5 и т. Д. Не очень хороши, потому что они слишком быстрые . Поскольку вы хотите использовать хеш для защиты, вам лучше использовать более медленные хеши. Посмотрите на Bcrypt , PBKDF2 или Scrypt , например.

редактировать : после наблюдений давайте попробуем увидеть некоторые моменты (извините, длинное объяснение до конца, потому что это может помочь другим в поиске похожих ответов):

Если ваша система безопасна, как никто и никогда не получит доступ к сохраненному паролю, вам не понадобится хеш. Пароль будет секретным, никто не получит его.

Но никто не может заверить, что база данных с паролями будет украдена. Украсть базу, получил все пароли. Хорошо, ваша система и ваша компания пострадают от всех последствий. Таким образом, мы могли бы попытаться избежать утечки этого пароля.

ОБРАТИТЕ ВНИМАНИЕ, что на данный момент мы не беспокоимся о сетевых атаках. Для одной онлайн-атаки лучшее решение - это замедлить работу после ввода неверных паролей, заблокировать учетную запись после нескольких попыток и т. Д. И для этого не имеет значения, каким образом вы шифруете, хешируете, сохраняете и т. Д. Свой пароль. Атака онлайн - это вопрос замедления ввода пароля .

Итак, вернемся к don't let them take my plain passwordsпроблеме. Ответ прост: не храните их в виде простого текста. Хорошо понял.

Как этого избежать?

Зашифруйте пароль (?). Но, как вы знаете, если вы шифруете его, вы можете расшифровать его обратно, если у вас есть соответствующий ключ. И вы столкнетесь с проблемой «где спрятать» ключ. Хм, ничего хорошего, так как они получили вашу базу данных, они могут получить ваш ключ. Хорошо, давайте не будем его использовать.

Итак, другой подход: давайте преобразуем пароль во что-то еще, что нельзя отменить, и сохраним его. И чтобы проверить правильность введенного пароля, мы снова делаем тот же процесс и проверяем, совпадают ли два преобразованных значения. Если они совпадают = хороший пароль был предоставлен.

Хорошо, пока все хорошо. Давайте используем некоторый хэш MD5 в пароле. Но ... если у кого-то есть сохраненное нами хешированное значение пароля, у него может быть много вычислительных мощностей для вычисления хеша MD5 каждого возможного пароля (грубой силы), чтобы он мог найти оригинальный пароль. Или, что еще хуже, он может хранить все MD5 из всех комбинаций символов и легко найти пароль. Итак, сделайте много итераций, HASH (HASH (HASH ())), чтобы сделать его сложнее, потому что это займет больше времени.

Но даже это можно обойти, радужный стол был создан именно для того, чтобы ускорить такую ​​защиту.

Итак, давайте использовать немного соли над ним. Таким образом, при каждом взаимодействии соль используется снова. Тот, кто пытается атаковать ваши пароли, должен будет создать радужную таблицу, учитывая, что соль добавляется каждый раз. И когда он сгенерирует эту радужную таблицу, так как она была сгенерирована с одной солью, ему придется снова вычислять с другой солью, поэтому ему придется потратить некоторое время на каждый пароль (= каждую соль). Соль не добавит «усложнения» к паролю, она просто заставит злоумышленника терять время на создание радужной таблицы. Если вы используете одну соль для каждого пароля, таблица из одной соли бесполезна для другого пароля.

И использование более чем одного хеша поможет здесь? Нет. Человек, генерирующий определенную атаку радуги, в любом случае сможет генерировать ее, используя один или несколько хэшей.

И использование более одного хеша может привести к одной проблеме: он так же безопасен, как и самый слабый хеш, который вы используете. Если кто-то обнаружит коллизии в одном алгоритме хеширования, то именно этот хеш будет использоваться в любой точке итерационного процесса для взлома пароля. Таким образом, вы ничего не получите, используя больше алгоритмов хеширования, лучше выбрать только один хороший алгоритм. и использовать это. И если вы когда-нибудь услышите, что он сломан, подумайте, как вы измените его в своем приложении.

И зачем использовать bcrypt или что-то подобное (вы говорите, что используете): потому что злоумышленнику придется тратить больше времени на создание таблиц. Вот почему использование MD5 + wait (3 секунды) не помогает: атака в любом случае будет автономной, поэтому злоумышленник может сгенерировать таблицы без (задержка в 3 секунды).

woliveirajr
источник
2
К сожалению! Извините, мой комментарий (о намеренном замедлении хэша с помощью параметра timeout) не должен восприниматься всерьез ... Я думаю, что в последнее время я слишком много читал о Дилберте.
FrustratedWithFormsDesigner
2
sha (sha (sha (...))) не более безопасен, чем sha. Если энтропия функции ша не максимальна, это на самом деле менее безопасно.
Deadalnix
1
@deadalnix: важно отметить, что это не облегчает восстановление исходного пароля, но облегчает генерацию пароля, который является обязательным.
Брайан Бетчер
1
@deadalnix, я прочитал этот комментарий голосом Дейла Гриббла .
Джигги
1
@deadalnix: цель sha (sha (sha ())) не состоит и никогда не была в том, чтобы добавить больше энтропии. Энтропия просто производится первоначальным пользователем, выбирающим свой пароль, а все остальное (хеш, соль и т. Д.) Просто для того, чтобы замедлить атаку методом грубой силы. Если кто-то может получить вашу базу данных, содержащую пароли, он, вероятно, также получит код, используемый для хеширования пароля, поэтому также известна любая жестко запрограммированная соль
woliveirajr
-1

Насколько я понимаю, использование нескольких алгоритмов хеширования - это победа радужных таблиц . Использование хорошей соли тоже работает, но, думаю, это второй уровень защиты.

Jiggy
источник
4
Ну, это не сильно меняет. Функцию «множественного хэша» можно рассматривать как единое целое и рассматривать как таковую.
Deadalnix
2
Использование нескольких методов хеширования или итераций не помогает победить радужные таблицы. Если у злоумышленника есть ваша база данных и метод, использованный для генерации хэшей, то злоумышленник может создать радужную таблицу для атаки на все пароли в базе данных. SALTS предотвращают атаки радужных таблиц, поскольку они не позволяют злоумышленнику создать один словарь поиска для атаки, скажем, на все пароли длиной не более 8 символов.
Эрик
-1

Это не более безопасно. Однако у вас есть протокол идентификации, основанный на хэше несколько раз с одной и той же функцией.

Это идет по этому пути. Сохраненное значение - хэш ^ n (передача) в компьютере A. A просит B аутентифицировать и дает B целое число n. B вычисляет хэш ^ (n-1) (проходит) и отправляет его обратно в A.

Проверка того, что хеш (хэш ^ (n-1) (передача)) == хэш ^ n (передача). Если это правда, то аутентификация завершена. Но тогда, Хэш магазина ^ (n-1) (проход) и следующая аутентификация, даст B n-1 вместо n.

Это гарантирует, что пароль никогда не будет передан в открытом виде, что A никогда не знает, что такое пароль, и что аутентификация защищена повтором. Однако у этого есть недостаток, требующий пароль с конечным сроком службы. Когда n достигает значения 2, новый пароль должен быть выбран после аутентификации.

Еще одно использование множественного хэширования - это инструмент HMAC, обеспечивающий аутентификацию и целостность запроса. Для получения дополнительной информации о HMAC см. Http://en.wikipedia.org/wiki/HMAC .

Большая часть использования множественного хэша в реальном мире является излишним. В вашем случае, похоже, так и есть. Обратите внимание, что если вы используете несколько хеш-функций, они не будут иметь одинаковую энтропию, поэтому это уменьшит силу хеш-функции. Например, md5 имеет меньшую энтропию, чем sha1, поэтому использование sha1 на md5 не улучшит силу хэша. Сила обычно будет равна силе более слабой хэш-функции.

deadalnix
источник