воскресенье, 16 октября 2016 г.

C#: Двухфакторная аутентификация без смартфона

Возникла тут интересная проблема. Если вкратце, то одна из "программ-от-знакомства-с-которыми-нельзя-отказаться" после смены версии вдруг вообразила себя крутой финансовой системой и затребовала двухфакторную аутентификацию. Не знаю, чем уж там разработчики соблазнили заказчиков, но теперь после ввода логина-пароля эта чудесная софтина показывает некий QR-код и предлагает пользователю установить на смартфон Google Authenticator, которому надо скормить этот её QR-код, чтобы этот GA начал генерировать PIN-коды, которые теперь будут дополнительно требоваться при входе. Короче, если хочешь поработать, покупай смартфон.

Меня, гордого пользователя Samsung SGH-X100 с периодически отваливающимся от старости аккумулятором, такое положение дел устроить никак не могло. Поэтому пришлось познакомиться с этим Google Authenticator-ом поближе. Как я понял, механизм тут такой.

Пусть есть клиент и сервер, и этот сервер хочет предоставить клиенту дополнительную защиту от взлома, даже если у этого самого клиента уведут пароль. Сервер предоставляет клиенту при первом входе некое уникальное число X0, которое клиент запоминает у себя и бережно хранит.

Когда клиент хочет аутентифицироваться на сервере, он берёт это число X0, текущее время T и применяет к ним описанную в стандарте детерминированную функцию F(X0, T), которая на выходе выдаёт PIN-код, передаваемый серверу. Сервер, в свою очередь, проделывает у себя ту же операцию, сравнивает полученный и рассчитанный PIN-коды и, если они совпадают, позволяет клиенту работать.

Как видим, алгоритм сильно зависит от того, насколько хорошо синхронизированы часы на сервере и у клиента. Чтобы упростить задачу, в алгоритме используется не количество, например, миллисекунд, прошедших с начала эпохи UNIX, а количество 30-секундных интервалов. То есть, допускается разбег между часами клиента и сервера в пределах 30 секунд.

Уникальное же число X0 как раз и предоставляется сервером клиенту в виде картинки с QR-кодом - видимо, для пущей безопасности.

Вооружившись этими знаниями, написал простенькую программку, используя которую можно считать этот QR-код с экрана и получать PIN-коды для двухфакторной аутентификации. Ну, то есть, хрен бы я чего написал, если бы не поиск Google, подсказки http://stackoverflow.com и волшебная библиотека MessagingToolkit.QRCode.dll.

Вот тут научился работать с получением всемирного координированного времени по протоколу NTP:
http://stackoverflow.com/questions/1193955/how-to-query-an-ntp-server-using-c

Вот тут рассказали, как получить снимок части экрана:
http://stackoverflow.com/questions/5049122/capture-the-screen-shot-using-net

Вот тут научили работать с base 32:
http://stackoverflow.com/questions/641361/base32-decoding

Вот тут нашелся рабочий код для Google Authenticator:
http://stackoverflow.com/questions/6421950/is-there-a-tutorial-on-how-to-implement-google-authenticator-in-net-apps

Вот тут (кажется) скачал библиотеку MessagingToolkit.QRCode.dll:
http://osdn.net/projects/sfnet_qrreader/downloads/MessagingToolkit.QRCode.dll/

Ну и, собственно, сам результат:

Программа

Исходники

UPD 2017-01-20: Как оказалось, история не закончилась. Нашлись QR-коды, на которых MessagingToolkit сбоит. Например, если QR-код содержит картинку-логотип. Пришлось перетащить проект на другую библиотеку, ZXing.NET

Программа (ZXing)

Исходники (ZXing)

А тут - небольшая памятка, как этой библиотекой пользоваться.

2 комментария:

  1. Здравствуйте!
    Спасибо за ваш труд!

    ОтветитьУдалить
  2. Вот это программа, а не черт знает что! Спасибо огромное!
    Пробовал другие проги, но помогла только ваша, остальные же выдавали длинный код, в котором не было ничего нужного.

    ОтветитьУдалить