1 октября 2014 г. Google Python Авторизация

Python. Двухфакторная авторизация через Google Authenticator

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

Для этого нам понадобится два файла:

  • "totp.py" - собственно реализация алгоритма TOTP;
  • "totp_auth.py" - хелпер для генерации и валидации токенов.

Пример работы

Создадим изолированное окружение, установим зависимости:

mkdir ~/work/totp && cd ~/work/totp
wget -O totp.py https://gist.githubusercontent.com/adw0rd/0a61f53dd7a61e5aa65c/raw/totp.py
wget -O totp_auth.py https://gist.githubusercontent.com/adw0rd/0a61f53dd7a61e5aa65c/raw/totp_auth.py
virtualenv --no-site-packages --distribute venv
. venv/bin/activate
pip install qrcode PIL

Создадим файл sample.py для демонстрации работы, со следующим содержимым:

Разберем работу sample.py. Сначала идет шаг регистрации двухфакторной авторизации пользователя и сохранения секретного ключа (SECRET):

  • Генерируем новый секретный ключ (SECRET);
  • Выводим QR-код;
  • Пользователь его сканирует через Google Authenticator;
  • Вводит в форму ввода на сайте полученный от Google Authenticator токен;
  • Если Пользователь ввел правилный токен, то мы сохраняем секретный ключ (SECRET) этому пользователю в БД, чтобы при авторизации использовался этот ключ для валидации токенов с Google Authenticator.

Запускаем:

$ python sample.py 
SECRET:  UG4QTQ6F4JI4BE3Y

Please input the token from Google Authenticator: 123123
FAILED (тут специально пользователь ввел неверный токен)
Please input the token from Google Authenticator: 613257  
SUCCESS (тут пользователь ввел верный токен, сохраняем SECRET в БД)

Теперь разберем шаги авторизации:

  • Пользователь входит на сайт и вводит правильные логин и пароль;
  • Если мы однозначно идентифицируем пользователя и для него уже есть секретный ключ (SECRET) в БД, то выводим ему QR-код по этому секретному ключу;
  • Он сканирует QR-код через Google Authenticator, либо среди свои аккаунтов находит уже созданный и вводит текущий токен на сайте;
  • Если он за указанное время ввел токен, то авторизация считается успешной иначе ему предлагается повторить попытку.

Запускаем с секретным ключем:

$ python sample.py UG4QTQ6F4JI4BE3Y
SECRET:  UG4QTQ6F4JI4BE3Y

Please input the token from Google Authenticator: 123123
FAILED (тут специально пользователь ввел неверный токен)
Please input the token from Google Authenticator: 394500
SUCCESS (тут пользователь ввел верный токен, можно его авторизовывать)

Таким образом мы реализовали двухфакторную авторизацию на базе TOTP и Google Authenticator. Постараюсь в ближайшее время на базе этой статьи сделать приложение для Django, которое будет хранить секретные ключи в БД и выводить QR-код когда это необходимо.

Комментарии

Есть для джанги уже django-secureauth

Да, для джанги уже куча таких либ, я уже решил ничего не писать

https://github.com/Bouke/django-two-factor-auth
https://github.com/mtigas/django-twofactor

Я для себя написал следующий код:

import hmac, base64, struct, hashlib, time, os

def clearShell():
    os.system(['cls'][os.name == os.sys.platform])

def HOTP(secret, intervals_no):
    key = base64.b32decode(secret, True)
    msg = struct.pack(">Q", intervals_no)
    h = hmac.new(key, msg, hashlib.sha1).digest()
    o = h[19] & 15
    h = (struct.unpack(">I", h[o:o+4])[0] & 0x7fffffff) % 1000000
    return h

def TOTP(secret):
    return HOTP(secret, intervals_no=int(time.time())//30)

S = {
    'Название': 'YOURSECRETCODE01',
    'Название': 'YOURSECRETCODE02'
}

lenght = 17 # Максимальная длина названия
line = ""
for i in range(0, lenght+18):
    line += "-"
line += "\n"

while True:
    text = line
    t = 30 - (int(time.time()) % 30)

    i = 0
    for s in S:
        i = i + 1

        code = TOTP(S[s])
        c1 = str(code//1000).rjust(3, '0')
        c2 = str(code %1000).rjust(3, '0')
        code = c1 + " " + c2

        text += "|  " + str(i).ljust(3, ' ') + " " + \
            s.ljust(lenght, ' ') + " " + code + "  |\n" + line

    text += "\n   ( " + str(t) + " с. )"

    clearShell()
    print(text)

    time.sleep(1)

Оставьте свой комментарий

Markdown