Как хешировать пароли в Python

hashlib сохранения пароля

В данном руководстве будет разобрано использование PBKDF2_HMAC для шифрования паролей вместе с солью в Python.

Содержание статьи

Зачем нужно хешировать пароли?

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

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

Есть вопросы по Python?

На нашем форуме вы можете задать любой вопрос и получить ответ от всего нашего сообщества!

Telegram Чат & Канал

Вступите в наш дружный чат по Python и начните общение с единомышленниками! Станьте частью большого сообщества!

Паблик VK

Одно из самых больших сообществ по Python в социальной сети ВК. Видео уроки и книги для вас!

Почему не стоит использовать SHA-256 или нечто похожее

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

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

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

Хеширование паролей с pbkdf2_hmac

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

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

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

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

PBKDF2_HMAC является реализацией функции получения ключа PBKDF2, использующей HMAC в качестве псевдослучайной функции. pbkdf2_hmac можно найти в библиотеке hashlib (которая поставляется с Python) и находится в Python 3.4 и выше. pbkdf2_hmac принимает пять параметров:

  • hash_name: алгоритм хеш дайджеста для HMAC;
  • password: пароль, превращенный в ключ;
  • salt: случайно сгенерированная соль;
  • iterations: итерации в вычислении (чем больше, тем длиннее вычисления);
  • dklen: длина ключа вывода (не обязательно).

Генерация соли в Python

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

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

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

Параметр 32 является размером, возвращаемым в байтах. Можно выбрать любой размер, но лучше не ставить значение более 16 байт.

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

Хеширование в Python

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

Так как длина ключа была предоставлена, используется размер дайджеста хеш алгоритма. В данном случае мы используем SHA-256, поэтому размер будет 64 байтов. Если нужен более длинный ключ для использования данного ключа в AES, требуется передать желаемый размер ключа dklen после итерации в hashlib.pbkdf2_hmac. Рассмотрим пример:

В данном примере ключом является ваш «хеш».

Хранение хеша и соли

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

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

Если можно использовать два места (в большинстве случаев так и есть), используйте. Это значительно облегчает процесс.

Проверка правильности пароля в Python

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

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

Пример регистрации пользователя с проверкой пароля