Python как создать двухфакторную авторизацию

В этом туториале вы научитесь использовать Pyotp для генерации 2FA кодов.

3 года назад я написал мини туториал про то как использовать pyotp для создания кодов. Но туториал получился не полным тк я не показал как все работает.

Обычно пользователи используют приложения авторизации вроде Authenticator для двух факторной авторизации. Такие приложения обычно поддерживают два протокола otp: TOTP, и HOTP. Подробнее как они работают мы разбирать не будем, просто нужно понимать что TOTP генерирует какую-то последовательность цифр на основе случайно сгенерированного ключа, и unixtime времени. Новый ключ появляется каждые 30 секунд.

Простые действия над PyOTP

Чтобы установить PyOTP нужно:

pip install pyotp

Чтобы использовать нам нужно, импортировать pyotp, и придумать секретный ключ, например "pythonforbeginers". Этот ключ потом пользователь будет вводить в Authenticator:

import pyotp
totp = pyotp.TOTP('base32secret3232')
totp.now()

Функция .now выводит 6 значный код авторизации на момент исполнения. Так же можно валидировать коды через функцию verify:

totp.verify(785367)

Эта функция выводит True либо False. Вы можете добавить код base32secret3232 в Authenticator, и получать точто такие же коды, как и totp.now(). Для работы с totp вам не требуется интернет подключение, тк коды генерируются на основе unixtime:
Unix-время — Определяется как количество секунд, прошедших с полуночи 1 января 1970 года;
Если на обоих устройствах стоит одинаковая дата, то они будут синхронизировано генерировать эти коды.

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

pyotp.random_base32()

Эта функция ввыводит рандомное значение которое можно использовать с Authenticator. Тк Authenticator поддерживает только base32 коды, лучше использовать этот готовый метод.

Чтобы пользоватся 2FA авторизацией в вашем веб проекте, вы должны добавить поле например "otp_code" к запросу на авторизацию, и когда пользователь посылает запрос на авторизацию вы должны проверить логин:пароль, получить id пользователя, затем по OneToOne связи выйти на код этого пользователя в таблице. Далее проверьте код через totp.verify, если это тоже правильно то можно авторизовать пользователя.

В реальном мире вам нужно будет защищатся от 2 типов атак: replay атака, и bruteforce.

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

Но об bruteforce нужно позаботится, тк TOTP даёт 6 значные коды, это всего лишь 999 999 комбинаций. Примерно столько запросов нужно отправлять будет за 30 секунд чтобы взломать 2FA код, поэтому нужно добавить throttling, чтобы например в минуту можно было отправить максимум 5 запросов с 1 IP адреса + максимум 20 запросов в день с одного 1 IP. Throttling есть во всех популярных библиотеках, например в DRF https://www.django-rest-framework.org/api-guide/throttling/ 

Комментарии

Популярные сообщения из этого блога

DOS атака при помощи Python

Ведем телеграм канал через питон

Django migrations не видит изменения моделей