• Перейти на CTF площадку Игры Кодебай

    Выполняйте задания по кибербезопасности в формате CTF и получайте бесценный опыт. Ознакомиться с подробным описанием можно тут.

Статья Используем двухэтапную (двухфакторную) аутентификацию в Python

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

000_0.png


Для создания небольшого демонстрационного приложения мы будем использовать библиотеку, которая как раз и предназначена для создания и валидации одноразового пароля. В англоязычном варианте такая аутентификация называется OTP, то есть, аббревиатура от слов one time password. Так как этот пароль одноразовый, то действует он только лишь в течении одного сеанса аутентификации. Также, действие пароля ограничено определенным промежутком времени. В нашем случае это 30 секунд. Если вы в течении 30 секунд не успели ввести одноразовый пароль, он изменится случайным образом. То есть, вводить уже нужно будет новые цифры.

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


Что потребуется?

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

pip install pyotp

Также нам понадобиться библиотека qrcode, с помощью которой мы будем генерировать QR-код, чтобы считать его с помощью любого приложения для OTP-аутентификации. Я использовал проприетарное решение от Google - Google Authenticator. Для установки библиотеки пишем в терминале команду:

pip install pyotp qrcode[pil]

И еще одна библиотека, которая вовсе не обязательна, но я ее использовал для открытия QR-кода после его генерации — это Pillow. Для ее установки пишем в терминале команду:

pip install Pillow

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

Python:
import pyotp
import qrcode
from PIL import Image

По большему счету, если добавить код открытия картинки с QR-кодом, то весь скрипт будет состоять из пары строк. Вот, собственно и они.

Python:
qrcode.make(pyotp.totp.TOTP("secretkey32figma").provisioning_uri(name='App', issuer_name='Apps')).save('otp.png')
Image.open("otp.png").show()

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

Python:
key = "secretkey32figma"
uri = pyotp.totp.TOTP(key).provisioning_uri(name='App', issuer_name='Apps')

qrcode.make(uri).save('otp.png')

Image.open("otp.png").show()

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

otpauth://totp/Apps:App?secret=secretkey32figma&issuer=Apps

Как видим, здесь передается секретный ключ, имя пользователя, и название приложения, которое будет использовать аутентификацию. Но, пользоваться такой ссылкой неудобно. Поэтому, с помощью библиотеки qrcode, создадим QR-code, в котором она и будет закодирована ссылка. Ну и далее, с помощью PIL открываем изображение. Код я изменил следующим образом.

Python:
# secretkey32figma

import pyotp
import qrcode
from PIL import Image


def generate(key):
    uri = pyotp.totp.TOTP(key).provisioning_uri(name='App', issuer_name='Apps')
    qrcode.make(uri).save('otp.png')
    Image.open("otp.png").show()


def main():
    key = input("Введите секретный ключ: ")
    if len(key) < 16:
        print("Длинна ключа должна быть не менее 16 символов. Повторите ввод.")
        main()
        return
    generate(key)


if __name__ == "__main__":
    main()

Теперь, чтобы использовать код для аутентификации нужно отсканировать его с помощью приложения для OTP-аутентификации. Как я писал выше, я использовал Google Authenticator. В данном случае, так как вы используете для генерации кода время, для конкретного отрезка времени аутентификации коды будут сгенерированы одинаковые как на стороне клиента, так и на стороне сервера, даже при отсутствии подключения к интернету.

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

Создадим отдельный питоновский файл, в котором напишем следующий код:

Python:
import binascii

import pyotp

key = 'secretkey32figma'
totp = pyotp.TOTP(key)

try:
    rs = totp.verify(input("Введите код аутентификации: "))
    print("Успешная аутентификация") if rs else print("Повторите ввод. Неудача.")
except binascii.Error:
    print("Перегенерируйте ключ. Длина ключа должна быть не менее 16 символов.")

Таким образом, мы берем секретный ключ, который использовался при генерации кода. Передаем его в библиотеку pyotp. Теперь, с помощью метода verify проверяем, совпадает ли ключ. В случае совпадения возвращается True, в случае неудачи — False. Ну и обработаем исключение, которое может возникнуть, если вы использовали при генерации ключ меньше 16 символов или без цифр.

01.png

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

Ну и, собственно, так выглядит Google Authenticator.

000.jpg

А на этом, пожалуй, все.

Спасибо за внимание. Надеюсь, информация была вам полезна
 
Последнее редактирование модератором:
Мы в соцсетях: