Содержание

Как надо хешировать пароли и как не надо / Хабр

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

Постараюсь очень лаконично и быстро обрисовать ситуацию с хэшами.

Сразу определю какую задачу применения хешей буду рассматривать — аутентификация пользователей. Не токены восстановления паролей, не аутентификация запросов, не что-то еще. Это также не статья про защиту канала передачи данных, так что комментарии по challenge-response и SSL неуместны!

Матчасть (короткая)
Hash = хеш функция — (свертка) функция однозначного отображения строки (любой длины) на конечное множество (строку заданной длины).
Само число (строка) хеш — результат вычисления хеш-функции над данными.
Существуют криптографические и некриптографические (классифицируются отдельно, к ним относятся, например, контрольные суммы) хеш-функции.

Для криптографических хэшей есть три дополнительных условия, которые отличают их от всех остальных:

  • Необратимость: для заданного значения хеш-функции m должно быть вычислительно неосуществимо найти блок данных X, для которого H(X)=m.
  • Стойкость к коллизиям первого рода: для заданного сообщения M должно быть вычислительно неосуществимо подобрать другое сообщение N, для которого H(N)=H(M).
  • Стойкость к коллизиям второго рода: должно быть вычислительно неосуществимо подобрать пару сообщений ~(M, M’), имеющих одинаковый хеш
Подробнее — ru.wikipedia.org/wiki/%D0%A5%D0%B5%D1%88%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5

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

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

Ниже перечислены требования, которым ваш хеш в базе должен удовлетворять:

  • стойкость к атакам перебора (прямой перебор и перебор по словарю)
  • невозможность поиска одинаковых паролей разных пользователей по хешам

Для выполнения первого требования нужно использовать стойкие в настоящее время (а не в 90х годах!) хеш-функции.
Для выполнения второго — к паролю перед хешированием добавляется случайная строка (соль). Таким образом, у двух пользователей с паролем «123456» будут разные соли «соль1» и «соль2», а соответственно и хеш-функции от «123456соль1» и «123456соль2» в базе тоже будут разные.

Теперь немного про систему хранения — и соль и сам хеш хранятся в базе данных.
То есть получив доступ к СУБД, злоумышленник получает и значения хешей и соли.

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

Для того чтобы еще усложнить жизнь атакующему, Solar Designer www.openwall.com/presentations/YaC2012-Password-Hashing-At-Scale/mgp00005.html предлагает ввести еще одну штуку, под названием локальный параметр.

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

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

Единственный раз мы (ONsec) ломали хеши с локальным параметром, выработав при этом тактику атаки на сам локальный параметр (регистрируемся в приложении, затем ищем в базе свой хеш, соль (свой пароль мы и так знаем) и перебираем ЛП). И тщетно. На длинах 16+ байт для современных функций хеширования — это очень дорого по железу. В итоге проще оказалось скомпрометировать систему аутентификации (проставить себе role=admin в базе через UPDATE 😉 )

Очень рекомендую ознакомиться с презентацией: www.openwall.com/presentations/YaC2012-Password-Hashing-At-Scale/mgp00001.html

Защищайте свои хранилища надежно и грамотно!

Заключение
Буду реалистом — естественно, никто не станет переписывать свои проекты ради «каких-то» хешей. Но новые проекты можно писать на scrypt/bcrypt. А также — внедряйте локальный параметр даже на слабых MD5 — он правда помогает, проверено 🙂

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

В заключении, привожу скорости перебора хешей (единицы измерения — мегахэши в секунду, то есть количество ), полученных на карточке AMD Radeon 7990 стоимостью менее $1000 (даже по старому курсу):

  • MD5: 16000 M/s
  • SHA-1: 5900 M/s
  • SHA256: 2050 M/s
  • SHA512: 220 M/s
  • NTLM: 28400 M/s
  • bcrypt: 8,5 k/s

А по поводу эффективности перебора bcrypt рекомендую также ознакомиться с www. openwall.com/presentations/Passwords13-Energy-Efficient-Cracking/Passwords13-Energy-Efficient-Cracking.pdf

PHP: Хеширование паролей — Manual

Change language: EnglishBrazilian PortugueseChinese (Simplified)FrenchGermanJapaneseRussianSpanishTurkishOther

Submit a Pull Request Report a Bug

В этом разделе разъясняются причины, стоящие за хешированием паролей в целях безопасности, а также эффективные методы хеширования.

  1. Почему я должен хешировать пароли пользователей в моем приложении?
  2. Почему популярные хеширующие функции, такие как md5 и sha1 не подходят для паролей?
  3. Если популярные хеширующие функции не подходят, как же я тогда должен хешировать свои пароли?
  4. Что такое соль?
  5. Как я должен хранить свою соль?
Почему я должен хешировать пароли пользователей в моем приложении?

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

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

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

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

Почему популярные хеширующие функции, такие как md5() и sha1() не подходят для паролей?

Такие хеширующие алгоритмы как MD5, SHA1 и SHA256 были спроектированы очень быстрыми и эффективными.

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

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

Если популярные хеширующие функции не подходят, как же я тогда должен хешировать свои пароли?

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

PHP предоставляет встроенное API хеширования паролей, которое безопасно работает и с хешированием и с проверкой паролей.

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

При хешировании паролей рекомендуется применять алгоритм Blowfish, который также используется по умолчанию в API хеширования паролей, так как он значительно большей вычислительной сложности, чем MD5 или SHA1, при этом по-прежнему гибок.

Учтите, что, если вы используете функцию crypt() для проверки пароля, то вам нужно предостеречь себя от атак по времени, применяя сравнение строк, которое занимает постоянное время. Ни операторы PHP == и ===, ни функция strcmp() не являются таковыми. Функция же password_verify() как раз делает то, что нужно. Настоятельно рекомендуется использовать встроенное API хеширования паролей, если есть такая возможность.

Что такое соль?

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

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

password_hash() создаёт случайную соль в случае, если она не была передана, и чаще всего это наилучший и безопасный выбор.

Как я должен хранить свою соль?

При использовании функции password_hash() или crypt(), возвращаемое значение уже содержит соль как часть созданного хеша. Это значение нужно хранить как есть в вашей базе данных, так как оно содержит также информацию о хеширующей функции, которая использовалась, и может быть непосредственно передано в функции password_verify() или crypt() при проверке пароля.

Следующая диаграмма показывает формат возвращаемого значения функциями crypt() или password_hash(). Как можно видеть, они содержат полную информацию об алгоритме и соли, требуемых для будущей проверки пароля.

add a note

User Contributed Notes 4 notes

up

down

145

alf dot henrik at ascdevel dot com

9 years ago

I feel like I should comment some of the clams being posted as replies here. 8 = 7,21389578984e+15 combinations.
With 100 billion per second it would then take 7,21389578984e+15 / 3600 = ~20 hours to figure out what it actually says. Keep in mind that you'll need to add the numbers for 1-7 characters as well. 20 hours is not a lot if you want to target a single user.

So on essence:
There's a reason why newer hash algorithms are specifically designed not to be easily implemented on GPUs.

Oh, and I can see there's someone mentioning MD5 and rainbow tables. If you read the numbers here, I hope you realize how incredibly stupid and useless rainbow tables have become in terms of MD5. Unless the input to MD5 is really huge, you're just not going to be able to compete with GPUs here. By the time a storage media is able to produce far beyond 3TB/s, the CPUs and GPUs will have reached much higher speeds.

As for SHA1, my belief is that it's about a third slower than MD5. I can't verify this myself, but it seems to be the case judging the numbers presented for MD5 and SHA1. The issue with speeds is basically very much the same here as well.

The moral here:
Please do as told. Don't every use MD5 and SHA1 for hasing passwords ever again. We all know passwords aren't going to be that long for most people, and that's a major disadvantage. Adding long salts will help for sure, but unless you want to add some hundred bytes of salt, there's going to be fast bruteforce applications out there ready to reverse engineer your passwords or your users' passwords.

up

down

24

swardx at gmail dot com

6 years ago

A great read..

https://nakedsecurity.sophos.com/2013/11/20/serious-security-how-to-store-your-users-passwords-safely/

Serious Security: How to store your users’ passwords safely

In summary, here is our minimum recommendation for safe storage of your users’ passwords:

    Use a strong random number generator to create a salt of 16 bytes or longer.
    Feed the salt and the password into the PBKDF2 algorithm.
    Use HMAC-SHA-256 as the core hash inside PBKDF2.
    Perform 20,000 iterations or more. (June 2016.)
    Take 32 bytes (256 bits) of output from PBKDF2 as the final password hash.
    Store the iteration count, the salt and the final hash in your password database.
    Increase your iteration count regularly to keep up with faster cracking tools.

Whatever you do, don’t try to knit your own password storage algorithm.

up

down

1

tamas at microwizard dot com

1 year ago

While I am reading the comments some old math lessons came into my mind and started thinking. Using constants in a mathematical algorythms do not change the complexity of the algorythm itself.

The reason of salting is to avoid using rainbow tables (sorry guys this is the only reason) because it speeds up (shortcuts) the "actual" processing power.
(((Longer stored hashes AND longer password increases complexity of cracking NOT adding salt ALONE.)))

PHP salting functions returns all the needed information for checking passwords, therfore this information should be treated as constant from farther point of view. It is also a target for rainbow tables (sure: for much-much larger ones).

What is the solution?
The solution is to store password hash and salt on different places.
The implementation is yours. Every two different places will be good enough.

Yes, it will make problems for hackers. He/she needs to understand your system. No speed up for password cracking will work for him/her without reimplementing your whole system.

This is my two cent.

up

down

4

fluffy at beesbuzz dot biz

11 years ago

The security issue with simple hashing (md5 et al) isn't really the speed, so much as the fact that it's idempotent; two different people with the same password will have the same hash, and so if one person's hash is brute-forced, the other one will as well.   This facilitates rainbow attacks.  Simply slowing the hash down isn't a very useful tactic for improving security.  It doesn't matter how slow and cumbersome your hash algorithm is - as soon as someone has a weak password that's in a dictionary, EVERYONE with that weak password is vulnerable.

Also, hash algorithms such as md5 are for the purpose of generating a digest and checking if two things are probably the same as each other; they are not intended to be impossible to generate a collision for.  Even if an underlying password itself requires a lot of brute forcing to determine, that doesn't mean it will be impossible to find some other bit pattern that generates the same hash in a trivial amount of time.

As such: please, please, PLEASE only use salted hashes for password storage.  There is no reason to implement your own salted hash mechanism, either, as crypt() already does an excellent job of this.

add a note

Как работают пароли?

 

Блог Delinea > Как работают пароли?

Поделиться:

Каждый раз, когда вы хотите совершить покупку, оставить комментарий на форуме или даже прочитать контент на многих веб-сайтах, вам будет предложено создать (и запомнить!) пароль.

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

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

Что такое хеширование и как оно работает?

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

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

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

  1. md5(helloworld) = fc5e038d38a57032085441e7fe7010b0
  2. md5(ад0мир) = 0a123b92f789055b946659e816834465
  3. md5(g84js;l238fl-242ldfsosd98234) = 42e7862f4ad5225471866d2023fc4cca#
  4. md5(helloworld) = fc5e038d38a57032085441e7fe7010b0

Из этих примеров мы можем узнать несколько вещей о хэшах:

Небольшие изменения имеют большое значение – Взгляните на примеры 1 и 2. Была смещена всего одна цифра с «o» на «0». Это очень небольшое изменение, и тем не менее второй вывод неотличим от первого.

Длина вывода никогда не меняется — Ввод в примере 3 значительно длиннее, чем в других примерах, но выдает ту же длину (32 символа). Вы можете ввести целую книгу в хэш-функцию md5(), и вы все равно получите 32-символьную строку в качестве вывода.

Повторяемый — ввод всегда будет давать один и тот же вывод при хешировании с использованием одной и той же функции. Если бы это было не так, они бы просто генерировали случайный вывод, который был бы бесполезен для паролей. (Я включил ту же функцию в пример 1, что и в пример 4, просто чтобы убедиться, что вы обратили внимание.)

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

Как используется хеширование пароля для предоставления доступа?

Давайте посмотрим, как хеширование работает на практике:

  • Шаг 1 — Пользователь посещает сайт и заполняет форму для создания своего имени пользователя и пароля.
  • Шаг 2 — Этот пароль подвергается хэш-функции, и хэш сохраняется в базе данных.
  • Шаг 3 — Когда пользователь входит в систему, он снова вводит свой пароль на сайте.
  • Шаг 4 — Введенный пароль обрабатывается той же функцией хеширования, что и раньше.
  • Шаг 5 — Сервер сверяет этот хеш с тем, который хранится для пользователя в базе данных.
  • Шаг 6 — Если два хэша точно совпадают, пользователю предоставляется доступ.

Достаточно ли хэширования для обеспечения безопасности паролей?

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

Как только киберпреступник получает хэши паролей с веб-сайта, начинается настоящий процесс взлома паролей. Этот процесс происходит в автономном режиме, на компьютере киберпреступника. Киберпреступники помещают комбинации символов в хеш-функцию, пока не будет создан хэш, соответствующий вашему.

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

Эти словари выходят далеко за рамки простых слов. Они включают в себя префиксы, суффиксы, практику замены букв на числа (например, 1 вместо l) и многое другое. Это означает, что слабые пароли могут быть взломаны очень быстро.

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

Для надежной защиты паролем необходимо:

  • Создать длинный и, казалось бы, случайный пароль
  • Периодически меняйте этот пароль
  • Никогда не используйте этот пароль повторно на других веб-сайтах

Не знаете, как создать надежный пароль? Попробуйте генератор надежных паролей Delinea.

PAM и управление паролями

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

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

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

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

Так вот как работают пароли! Теперь узнайте больше об управлении привилегированным доступом.

Связанные материалы: почему НЕ следует хранить корпоративные пароли в Excel.


Выявляйте опасные сохраненные пароли за считанные минуты

Наш бесплатный инструмент обнаружения скрытых паролей, хранящийся в браузере.

ПОЛУЧИТЬ ИНСТРУМЕНТ

Основы PAM, Киберустойчивость

Другие посты, которые могут вам понравиться

Дорога с односторонним движением к усиленной безопасности

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

Хранение паролей рискованно и сложно

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

Уровень безопасности и отказоустойчивость этой модели зависит от как хранится пароль . Самый простой, но и наименее безопасный формат хранения паролей — открытый текст .

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

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

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

Более безопасный способ хранения пароля — преобразовать его в данные, которые нельзя преобразовать обратно в исходный пароль. Этот механизм известен как хеширование . Давайте узнаем больше о теории хеширования, его преимуществах и ограничениях.

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

Твитнуть это

О чем хеширование?

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

В криптографии хэш-функция — это математический алгоритм, который отображает данные любого размера в битовую строку фиксированного размера. Мы можем ссылаться на ввод функции как сообщение или просто как ввод. Выходные данные строковой функции фиксированного размера известны как хэш или дайджест сообщения . Согласно OWASP, хэш-функции, используемые в криптографии, обладают следующими ключевыми свойствами:

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

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

Обычно используемые алгоритмы хеширования включают алгоритмы Message Digest (MDx), такие как MD5, и безопасные алгоритмы хэширования (SHA), такие как SHA-1 и семейство SHA-2, которое включает широко используемый алгоритм SHA-256. . Позже мы узнаем о силе этих алгоритмов и о том, как некоторые из них устарели из-за быстрого прогресса в области вычислений или перестали использоваться из-за уязвимостей в системе безопасности.

В биткойнах целостность и цепочка блоков используют алгоритм SHA-256 в качестве базовой криптографической хэш-функции. Давайте рассмотрим пример хеширования с использованием SHA-256 и Python.

Если вы хотите продолжить, вы можете использовать онлайн-среду Python repl.it IDE для простого запуска сценариев Python.

IDE Python repl.it предоставляет вам редактор кода для ввода кода Python, кнопки для сохранения или запуска скрипта и консоль для визуализации вывода скрипта.

В редакторе кода введите следующую команду, чтобы импортировать метод конструктора хеш-алгоритма SHA-256 из hashlib module:

 from hashlib import sha256 

В строке ниже создайте экземпляр класса sha256 :

 h = sha256() 

Затем используйте обновление () способ обновления Хэш -объект:

 H. Update (B'Python1990K00L ') 

Тогда используйте метод Hexdigest () , чтобы получить Digest строки, переданный в Update () Method:

7 HASHH h hh h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h. .hexdigest() 

Дайджест — это результат хэш-функции.

Наконец, напечатайте переменную hash , чтобы увидеть значение хеша в консоли:

 print(hash) 

Полный скрипт выглядит так: ч = ша256 () h.update(b’python1990K00L’) хэш = h.hexdigest() print(hash)

Чтобы запустить скрипт, нажмите кнопку «Выполнить» в верхней части экрана. В консоли вы должны увидеть следующий вывод:

 d1e8a70b5ccab1dc2f56bbf7e9.9f064a660c08e361a35751b9c483c88943d082 

Напомним, вы предоставляете хеш-функции строку в качестве входных данных и получаете в качестве выходных данных другую строку, представляющую хешированные входные данные:

Ввод:

901 66 python1990K00L

Хэш (SHA-256):

d1e8a70b5ccab1dc2f56bbf7e99f064a660c08e361a35751b9c483c88943d082

Попробуйте хэшировать строку python . Вы получили следующий хэш?

 11a4a60b518bf24989d481468076e5d5982884626aed9faeb35b8576fcd223e1 

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

Tweet This

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

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

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

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

Криптографические хэш-функции практически необратимы

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

Оператор по модулю дает нам остаток от деления. Например, 5 mod 3 равно 2 , поскольку остаток от 5 / 3 равен 2 при целочисленном делении. Эта операция является детерминированной, поскольку одни и те же входные данные всегда дают один и тот же результат: математически 5 / 3 всегда приводит к 2 . Однако важной характеристикой операции по модулю является то, что мы не можем найти исходные операнды, учитывая результат. В этом смысле хеш-функции необратимы.

Знание того, что результатом операции по модулю является 2 , говорит нам только о том, что x , деленное на y , напоминает 2 , но ничего не говорит нам о x и y 9 0167 . Существует бесконечное количество значений, которыми можно заменить x и y на x mod y , чтобы получить 2 :

 7 mod 5 = 2
9 по модулю 7 = 2
2 по модулю 3 = 2
10 по модулю 8 = 2
... 

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

Если вам интересно, как работает хеш-функция, эта статья в Википедии содержит все подробности о том, как работает алгоритм безопасного хеширования 2 (SHA-2).

Небольшое изменение имеет большое значение

Еще одним достоинством защищенной хеш-функции является то, что ее результат нелегко предсказать. Хэш для dontpwnme4 будет сильно отличаться от хэша для dontpwnme5 , даже если изменится только последний символ в строке, и обе строки будут соседними в отсортированном по алфавиту списке:

Ввод:

dontpwnme4

Хэш (SHA-256):

4420d1918bbcf7 686defdf9560bb5087d20076de5f77b7cb4c3b40bf46ec428b

Ввод:

dontpwnme5

9 0035 Хэш (SHA-256) :

3fc79ff6a81da0b5fc62499d6b6db7dbf1268328052d2da32badef7f82331dd6

Вот скрипт Python, используемый для расчета этих значений, если вам это нужно:

 из hashlib импорта sha256
ч = ша256 ()
h. update(b'')
хэш = h.hexdigest()
print(hash) 

Замените на нужную строку для хеширования и запустите ее на repl.it.

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

Следовательно, мы не можем определить, какой хеш dontpwnme6 будет основан на двух предыдущих хэшах; вывод непоследовательный.

Использование криптографического хеширования для более безопасного хранения паролей

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

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

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

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

Уникальность является ключевым свойством солей; длина помогает уникальности.

Ограничения хеш-функций

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

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

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

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

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

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

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

Нет необходимости в скорости

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

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

Атаки столкновений не рекомендуют хэш-функции

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

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

Источник: Объявление о первом столкновении SHA1 (Google)

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

Tweet This

Для простых алгоритмов хэширования простой поиск в Google позволит нам найти инструменты, которые преобразуют хэш обратно в открытый текст. Алгоритм MD5 сегодня считается опасным, и Google объявила о первой коллизии SHA1 в 2017 году. Оба алгоритма хэширования были признаны небезопасными для использования и объявлены устаревшими Google из-за возникновения криптографических коллизий.

Google рекомендует использовать более надежные алгоритмы хеширования, такие как SHA-256 и SHA-3. Другими часто используемыми на практике вариантами являются bcrypt , scrypt и многие другие, которые вы можете найти в этом списке криптографических алгоритмов. Однако, как мы выяснили ранее, одного хеширования недостаточно, и его следует сочетать с солями. Узнайте больше о том, как добавление соли к хешированию — лучший способ хранения паролей.

Резюме

Давайте подытожим то, что мы узнали из этой статьи:

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