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

В данном руководстве будет разобрано использование 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, которая возвращает случайные байты, используемые для шифрования. Данная функция не использует генераторы псевдослучайных чисел, поэтому возвращаемое значение нельзя предугадать. Как раз то, что нам нужно.
Python-сообщество
![]()
- Начало
- » Python для новичков
- » Менеджер паролей
#1 Янв. 18, 2021 01:32:45
isd2020 Зарегистрирован: 2021-01-05 Сообщения: 5 Репутация: 0 Профиль Отправить e-mail
Менеджер паролей
Добрый день знатоки.
Подскажите пожалуйста ресурс на котором можно посмотреть рабочий код менеджера пользователей-паролей. (Или может у кого то есть)
Учусь.. хотелось бы изучить эту тему.
Идея в том чтобы можно было создавать редактировать пользователя, его роль, устанавливать пароль.
По возможности хранить все это в ТХТ…
Система для учебы поэтому не сильно пережтваю за кражу данных и тд.
#2 Янв. 18, 2021 04:04:29
py.user.next От: Зарегистрирован: 2010-04-29 Сообщения: 9629 Репутация: 839 Профиль Отправить e-mail
Менеджер паролей
isd2020
код менеджера пользователей-паролей
Это база данных и клиент к ней. Соответственно, тебе нужно изучать проектирование баз данных, написание клиентов для баз данных и шифрование данных с симметричным ключом. Если тебе консольный клиент не подходит, можно изучать создание приложений с графическим интерфейсом. То есть это всё разные вещи, отдельные, которые вообще друг с другом не связаны. Ты просто каждую часть делаешь из её области, а потом эти части соединяешь вместе. И тогда у тебя получится менеджер паролей, который состоит из независимых частей, обменивающихся друг с другом информацией.
#3 Янв. 19, 2021 06:32:14
doza_and От: Зарегистрирован: 2010-08-15 Сообщения: 4138 Репутация: 252 Профиль Отправить e-mail
Менеджер паролей
База данных тут вовсе не обязательна. ну по крайней мере классическая бд.
isd2020
По возможности хранить все это в ТХТ…
isd2020
не сильно пережтваю за кражу данных и тд.
isd2020
код менеджера пользователей-паролей
Мне кажется ваши устремления внутренне противоречивы. Если вы не опасаетесь кражи и всем доверяете зачем вам пароли?
Хранение секретных паролей в открытом виде в текстовых файлах – противоречит основам кибербезопрасности.
Начните с того что распишите как вы эти роли и пароли собираетесь применять. Тогда будет яснее что вам посоветовать.
#4 Янв. 19, 2021 09:56:21
PEHDOM Зарегистрирован: 2016-11-28 Сообщения: 2196 Репутация: 294 Профиль Отправить e-mail
Менеджер паролей
doza_and
Мне кажется ваши устремления внутренне противоречивы. Если вы не опасаетесь кражи и всем доверяете зачем вам пароли?
человек же ясно написал “Система для учебы”
isd2020 ну вот например можете посмотреть :
https://github.com/gabfl/vault
https://github.com/0x27/GitPass
Но там для хранения паролей используют БД или Гитхаб…
Если совсем для учебы можете хранить пароли в шифрованом виде в txt файле, где ключем шифрования будет выступать masterpassword, тут вообще все просто.. как писать-читать из файла можно найти в любом туториале по пайтону + чутка криптографии https://coderlessons.com/tutorials/python-technologies/izuchite-kriptografiiu-s-python/kriptografiia-s-python-kratkoe-rukovodstvo
В более сложном варианте masterpassword служит только ключем к рандомносгенерированму ХХХ-битному ключу,а уже пароли шифруються этим рандомносгенерированым ключем.
[code python][/code]
Бериегите свое и чужое время.
Отредактировано PEHDOM (Янв. 19, 2021 10:00:44)
Хранение логина и пароля
Всем доброго времени суток. В общем возник вопрос, как хранить пароли и логины от Яндекса. Хранить в БД не вариант, ибо любая система может быть скомпроментирована. Есть ли способ хранить логин и праоль локально пердавая в запрос, где получается id сессии и она уже будет храниться в базе.
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
Ответы с готовыми решениями:
Хранение логина и пароля в базе
Сделал авторизацию при входе в базу, храню логин и пароль в одной из таблиц базы. База клиент -.
Хранение логина и пароля от сервера
Юзаю компонент SFTP от Clever Components, который использует SSH для подсоединению к серверу.
Хранение Уникального ключа, Токена, Логина и пароля
Всем привет, здесь пойдет речь о хранение ключей, токена и имя пользователя. Сразу хочу отметить.
Форма изменения пароля, убрать автоподстановку логина-пароля
У меня форма которая должна проверить старый пароль и изменить, классы инпутов названы.
Проверка логина и пароля
<? include(‘config.php’); $log=$_POST; $pas=$_POST; $pas=MD5($pass);.
Регистрация пользователей и шифрование паролей
После некоторого отступления на прошлых занятиях, посвященных обработке, перехвату запросов, а также кукам и сессиям, я возвращаюсь к нашему тестовому сайту и продолжу его совершенствование.
У нас с вами были сформированы функции представления для главной страницы, а также для добавления статьи и ее отображения. Во всех этих функциях имеется общий код соединения с БД, который следует вынести как бы за скобки и описать в функции декоратора before_request:
dbase = None @app.before_request def before_request(): """Установление соединения с БД перед выполнением запроса""" global dbase db = get_db() dbase = FDataBase(db)
А в функциях обработчиках запросов это соединение просто использовать.
Подготовка форм авторизации и регистрации
Теперь предположим, что на нашем сайте мы хотели бы выполнять регистрацию и авторизацию пользователей. С чего здесь следует начать? Для начала добавим пункт в главное меню «Авторизация», т.е. в БД таблицы mainmenu следует создать запись:
И, затем, добавим функцию представления для URL /login:
@app.route("/login") def login(): return render_template("login.html", menu=dbase.getMenu(), title="Авторизация")
Создадим шаблон login.html:
{% extends 'base.html' %} {% block content %} {{ super() }} {% for cat, msg in get_flashed_messages(True) %} div class="flash >">{{msg}}/div> {% endfor %} form action="/login" method="post" class="form-contact"> p>label>Email: /label> input type="text" name="email" value="" requied /> p>label>Пароль: /label> input type="password" name="psw" value="" requied /> p>input type="checkbox" name="remainme" /> Запомнить меня p>input type="submit" value="Войти" /> hr align=left width="300px"> p>a href=">">Регистрация/a> /form> {% endblock %}
Здесь у нас простая форма авторизации по Email и паролю, а также имеется ссылка на страницу регистрации, если пользователь еще не зарегистрирован.
Соответственно, в программе нужно добавить обработчик для регистрации:
@app.route("/register") def register(): return render_template("register.html", menu=dbase.getMenu(), title="Регистрация")
И прописать шаблон register.html:
{% extends 'base.html' %} {% block content %} {{ super() }} {% for cat, msg in get_flashed_messages(True) %} div class="flash >">{{msg}}/div> {% endfor %} form action="/register" method="post" class="form-contact"> p>label>Имя: /label> input type="text" name="name" value="" requied /> p>label>Email: /label> input type="text" name="email" value="" requied /> p>label>Пароль: /label> input type="password" name="psw" value="" requied /> p>label>Повтор пароля: /label> input type="password" name="psw2" value="" requied /> p>input type="submit" value="Регистрация" /> /form> {% endblock %}
Здесь все очень похоже на форму авторизации, только прописаны другие поля и обработка данных по запросу /register.
После всего этого подготовительного этапа, пришло время создать таблицу в БД, которая бы хранила данные о зарегистрированных пользователях. Мы ее сделаем простой: назовем users и определим следующие поля:
CREATE TABLE IF NOT EXISTS users ( id integer PRIMARY KEY AUTOINCREMENT, name text NOT NULL, email text NOT NULL, psw text NOT NULL, time integer NOT NULL );
Создадим ее в БД, выполним функцию create_db в консоли Python:
from flsite import create_db create_db()
Если кто не помнит, мы эту функцию создавали ранее, когда говорили об использовании БД во Flask. Я не буду здесь останавливаться на этом моменте, если есть необходимость, просто посмотрите это видео.
Шифрование паролей в БД
Итак, мы создали таблицу users в БД flsite и пришла пора ее наполнить, т.е. написать функционал, который бы добавлял нового пользователя в эту таблицу. Как это правильно сделать? Если мы будем создавать записи один в один с введенными значениями в форме регистрации, то в поле psw пароли будут храниться в открытом (не защищенном) виде:

Такие данные быстро утекут, чего бы вы не делали: вашему системному администратору сделают предложение, от которого он не сможет отказаться и передаст всю информацию злоумышленнику. Или он сам ими воспользуется. Короче, хранить приватные данные в открытом виде в БД – это верх безрассудства, их нужно зашифровать. Благо для этого была придумано масса математических алгоритмов и во Flask можно использовать один из них, определяемый стандартом
PBKDF2 (Password-Based Key Derivation Function)
который доступен из пакета
устанавливаемый совместно с Flask.
Общий принцип шифрования информации у всех алгоритмов един: на выходе формируется на первый взгляд случайная последовательность символов, которая уникальная для исходных кодируемых данных. Например, для пароля 12345 получим следующую последовательность по стандарту PBKDF2:
В шифровании это называется хешем закодированных данных. И глядя на этот хеш, совершенно непонятно что в нем записано. Причем, нет обратного алгоритма декодирования, который бы из этой строки получал пароль 12345. Поэтому, у злоумышленников здесь только один вариант – полный перебор. То есть, перебирать все возможные варианты паролей, кодировать их и сравнивать полученный хеш с хешем в БД. Но это очень долгий и сложный путь. Поэтому так важно им знать приватную информацию в чистом виде. И мы им такой радости не доставим, все нужное будем кодировать! А как мы тогда на сервере проверим, например, корректность ввода пароля? Для этого, пароль, указанный пользователем подвергается шифрованию и, затем, сравниваются между собой их хеши. Если они равны, значит, пароль верный.
Итак, как во Flask выполнять кодирование и последующую проверку пароля. Для этого из пакета Werkzeug нужно импортировать следующие функции:
from werkzeug.security import generate_password_hash, check_password_hash
- generate_password_hash() – выполняет кодирование строки данных по стандарту PBKDF2;
- check_password_hash() – выполняет проверку указанных данных на соответствие хеша.
hash = generate_password_hash("12345")
а для проверки:
check_password_hash(hash, "12345")
Последняя функция вернет True, если хеши совпадают и False в противном случае.
Добавление пользователя в БД
Теперь, когда мы знаем как шифровать данные, запишем в обработчик функционал для добавления пользователя в таблицу users. Вначале нужно импортировать функции для шифрования и проверки паролей:
from werkzeug.security import generate_password_hash, check_password_hash
А затем, реализовать обработчик формы. Я не буду здесь усложнять программу и представлю простой обработчик для данных формы регистрации:
@app.route("/register", methods=["POST", "GET"]) def register(): if request.method == "POST": session.pop('_flashes', None) if len(request.form['name']) > 4 and len(request.form['email']) > 4 \ and len(request.form['psw']) > 4 and request.form['psw'] == request.form['psw2']: hash = generate_password_hash(request.form['psw']) res = dbase.addUser(request.form['name'], request.form['email'], hash) if res: flash("Вы успешно зарегистрированы", "success") return redirect(url_for('login')) else: flash("Ошибка при добавлении в БД", "error") else: flash("Неверно заполнены поля", "error") return render_template("register.html", menu=dbase.getMenu(), title="Регистрация")
Здесь все достаточно очевидно и нам нужно еще прописать метод addUser во вспомогательном классе FDataBase:
def addUser(self, name, email, hpsw): try: self.__cur.execute(f"SELECT COUNT() as `count` FROM users WHERE email LIKE ''") res = self.__cur.fetchone() if res['count'] > 0: print("Пользователь с таким email уже существует") return False tm = math.floor(time.time()) self.__cur.execute("INSERT INTO users VALUES(NULL, ?, ?, ?, ?)", (name, email, hpsw, tm)) self.__db.commit() except sqlite3.Error as e: print("Ошибка добавления пользователя в БД "+str(e)) return False return True
Сначала идет проверка на уникальность email для пользователя и если указанного email не существует, то пользователь добавляется в БД.