После публикации статьи «TOTP без смартфона» она получила много интересных и полезных комментариев. Я решил подождать, пока обсуждение затихнет и провести работу над замечаниями и высказанными мыслями.

Поскольку объём работы оказался достаточно большой, то оформил её в виде отдельной публикации-послесловия.

Философские вопросы (фактор знания или владения?)

В идеальной модели MFA первый фактор предполагается фактором знания (пароль), а второй — фактором владения (вот типа мой номер телефона для СМС, или смартфон с генератором кодов, или аппаратный ключ).

Увлекательная дискуссия развернулась по поводу того, что же может считаться знанием, а что владением; как одно может перетекать в другое; что можно скопировать, а что потерять / отобрать. Огромное спасибо уважаемым @splitfire, @aborouhin, @inkelyad как застрельщикам этой ветки!

Раздельное хранение разных FA

Хотя само по себе наличие 2FA увеличивает защищённость сервиса по сравнению с одним лишь паролем (отпадают угрозы утечки пароля, банальное подсмотрели или более сложные варианты, типа кейлоггер / анализ звука клавиатуры etc) — идеологически правильным будет хранить 2FA отдельно, таким образом, который исключает возможность одновременного раскрытия и пароля, и TOTP.

Поэтому я прекратил использование KeePass для хранения секретов TOTP (хоть это и казалось очень удобным, но безопасность обычно обратно пропорциональна удобству, и наоборот). Да, можно использовать отдельную парольную базу для 2FA, но это уже не будет удобно; а безопасно хранить их в GPG зашифрованном виде уже реализовано.

Использование 2FA на отдельном устройстве

Спасибо уважаемому @xSVPx за мысль:

Смысл двухфакторной проверки в том, что оба "пароля" в том числе хранятся или получаются способами не имеющими общих мест. Т.е. для компрометации необходимо два устройства взломать, а не одно.

Действительно, даже при раздельном хранении разных FA на одном и том же устройстве (например, рабочий десктоп) существует угроза раскрытия всех FA при его полной компрометации. Поэтому я храню 2FA на отдельной Linux-машине, доступной через SSH. Для пущей надёжности заходить на неё можно не с основного десктопа, а с рабочего ноутбука.

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

2FA и Microsoft

Я не до конца разобрался с тонкостями 2FA в Microsoft, когда написал:

не работает с MicroSoft, поскольку там традиционно не ограничились стандартным TOTP

Спасибо уважаемым @aborouhin и @CaptainFlint за то, что обратили моё внимание на это и побудили ещё раз пройти через не очень очевидные настройки безопасности учётной записи MicroSoft.

Как оказалось, при включении 2FA есть возможность выбрать опцию другая программа–аутентификатор, тогда вместо проприетарной связи с приложением Microsoft Authenticator на телефоне — сгенерируют QR-код (нормально воспринимается например Google Authenticator); а с опцией не могу отсканировать QR можно получить заветный TOTP секрет в формате base32. После чего он без проблем работает с mytotp.sh (с теми же дефолтными шестью цифрами и хэшем SHA-1).

Извлечение параметров TOTP из Google Authenticator

Уважаемый @adrozhzhov поделился методикой извлечения параметров TOTP, уже заведённых в Google Authenticator. Нужно в приложении инициировать Transfer Accounts, выбрать нужный нам из списка, получив QR-код сделать скриншот экрана и нажать Cancel.

Для дальнейшей работы нужна программа zbarimg для декодирования QR-кода (пакет zbar-tools в Debian и производных, zbar в RedHat и производных) и скрипт для разбора строки otpauth-migration (Python3 с двумя зависимостями, ставится с GitHub)

 $ sudo apt install zbar-tools
 $ cd ~/wrk && git clone https://github.com/qistoph/otp_export
 $ cd otp_export && pip install -r requirements.txt
 $ ./parse.py "$(zbarimg -q --raw  /path/to/qr-auth.png)"
 [...]
  secret: b'ABCD1234EFGH5678IJKL2345MNOP6789'
  name: myname@service
  issuer: 
  algorithm: SHA1
  digits: SIX
  type: TOTP

Новый вариант скрипта (форк на GitHub)

Мысль следовать моде и разместить свой тривиальный скрипт на GitHub оказалась удачной: репозиторий был дважды форкнут, причём во втором случае доработан до использования в виде BASH-функций mytotp(), mytotpadd() и mytotplist() для загрузки в окружение и последующего вызова. Более того, уважаемый yuriq оформил pull request на включение изменений в мой репозиторий, всё как у взрослых!

Думаю теперь, как лучше поступить — с одной стороны, изменения полезные; с другой я достаточно старомоден и стараюсь не раздувать окружение BASH, потому надо бы и исходный вариант со скриптом оставить. Осталось поизучать мануалы на git(1) а также best practices на GitHub, чтобы всё сделать правильно и красиво.

Аппаратный токен U2F

Уважаемый @kasiopei задал вопрос про U2F устройства:

А почему U2F почти никто не внедряет? Не знают о нем или защита слабая?

Поскольку мои познания в этом вопросе были сугубо теоретическими, я решил расстаться с небольшой суммой денег и поискал доступное к покупке прямо сейчас устройство с поддержкой форматов FIDO U2F (CTAP1) / FIDO2 (CTAP2).

Устройства Yubikey мне показались дороговатыми, плюс табличка The FIDO U2F PIN озадачила богатством вариантов — взял USB-устройство попроще. И вот что я хочу сказать:

Это лучшее решение задачи «TOTP без смартфона»!

От GAuth к CTAPx
От GAuth к CTAPx

Работает со всеми моими сервисами (думаю, в 2024 году большинство веб-сервисов поддерживают CTAP); под Windows (7 / 10), MacOS (10.13+), Linux (Mint 21); с актуальными версиями FireFox и Safari (уверен, с Chrome тоже работать будет). Если не устанавливать свой PIN на токен (чистый фактор владения), то вообще ничего с ним делать не нужно, помимо:

  • Регистрация: зашли на сервис, выбрали настройку 2FA, аппаратный ключ; когда попросят — коснулись кнопки на ключе

  • Использование: зашли на сервис, увидели приглашение коснуться кнопки на ключе, коснулись — аутентификация выполнена

Из недостатков (кроме необходимости заплатить живые деньги): при поломке / пропаже токена остаёмся без 2FA. В Apple даже предлагают при активации 2FA использовать два разных токена; но вполне можно обойтись схемой «токен + TOTP», чем я и воспользовался.

Заключение

Итак, обозначенная задача решена мною теперь уже двумя способами: совершенным (но за деньги и не копируется) и чуть попроще (но бесплатно и подлежит резервному копированию).

Хочу поблагодарить всех участников дискуссии, которые не были упомянуты выше, за ваши высказанные мнения и замечания; а также уважаемую @Exosphere за терпеливые ответы на мои новичковые вопросы при подготовке публикации.

Комментарии (31)


  1. Wesha
    22.04.2024 22:26
    +1

    В имеющихся 2FA жутко бесит, что время должно быть достаточно точно синхронизировано между девайсами — а если второе устройство не имеет контактов с внешним миром, то время имеет тенденцию убегать, и в результате сгенерированный код не подходит. Другая проблема — часовые пояса: поскольку я нахожусь не в Москве, постоянно приходится на девайсе выставлять московское время, чтобы код для Сбера оказался правильный. Есть же для таких ситуаций UTC, которое по всему шарику одно и то же — но индейская народная национальная изба получается...


    1. mmMike
      22.04.2024 22:26
      +5

      Поскольку не раз реализовывал и использовал TOTP в разных проектах, то описанная ситуация несколько удивляет.

      время имеет тенденцию убегать

      У TOTP есть параметр "период" и его редко ставят меньше 30 сек. Устройство в котором время убегает от сервера на хотя бы 5 сек (что бы это вызвало проблемы) за какой то разумный срок (месяц..два) без синхронизации - это странно.

      постоянно приходится на девайсе выставлять московское время, чтобы код для Сбера оказался правильный. Есть же для таких ситуаций UTC

      То же очень странно. В стандартной реализации, на хосте у меня используется Math.floorDiv(System.currentTimeMillis()/1000L, period) и никаких проблем нет с UTC временем ни с одним сторонним токеном TOTP.
      Потому что, по стандарту rfc6238 используется время UTC и никаких часовых поясов нет в принципе.


      1. Wesha
        22.04.2024 22:26

        У меня на "телефоне" (аппарат, у которого нет симки, то есть это просто "мобильный WiFi-терминал" время регулярно убегает на 2-3 минуты (Без симки синхронизировать время с сотовой сетью он почему-то не умеет), а установка "текущего времени" осуществляется как "укажи на циферблате, куда стрелки показывают" (а не "набери цифирки на клавиатуре"), в результате чего правильный TOTP-код получается попыткий так с пятой.

        То же очень странно. В стандартной реализации,

        Очевидно, у сберовских программистов своеобразные понятия о том, что такое "стандартная реализация" (ни разу не удивлён, кстати, велосипед из костылей — наше всё). При установке правильной таймзоны и правильного текущего местного времени — индейская изба; при установке таймозны "Москва" и текущего московского времени — работает.


        1. ThingCrimson Автор
          22.04.2024 22:26

          Кстати, если у Вас часы на устройстве отстают — попробуйте oathtool -w 10 скажем. Это сгенериует TOTP для текущего момента времени плюс 10 последующих периодов (30 секунд рекомендовано). Можно изловчиться в уме коррекцию делать: «ага, отстаём на две минуты, значит беру пятое выданное значение TOTP».

          А вот если спешат, тогда хуже… Ну и привязка к конкретной таймзоне остаётся — если бы в РФ была одна таймзона на всю страну, можно было бы сказать «так и задумано, чтоб только свои могли пользоваться», а так даже и не знаю.


          1. CaptainFlint
            22.04.2024 22:26
            +1

            А вот если спешат, тогда хуже…

            Ничто не мешает точно так же сгенерировать код на любой момент времени, в том же oathtool можно задать произвольное время, а не только несколько будущих кодов. При желании можно даже скрипт наклепать, который запросит текущее время с какого-нибудь интернет-ресурса, сделает коррекцию на таймзону и вставит это значение в параметры oathtool'у вместо текущего. Другой вопрос, что запускать консольные программы на смартфоне — удовольствие ниже среднего, не говоря уж о том, что секретный код для генерации придётся тогда хранить не в конкретном приложении, а в общедоступной части файловой системы.


            1. ThingCrimson Автор
              22.04.2024 22:26

              Да, Вы правы, можно делать нечто вроде такого oathtool -N $(date -ud "2 minutes 25 seconds ago")

              Что касается консольных программ на смартфоне (хотя я именно от смартфона и старался уйти), то при наличии там полноценного линукса (iSH для iPhone, наверняка для Android есть аналог) — можно поставить туда кроме oathtool ещё и GPG, ну и mytotp.sh тогда тоже.

              (в сторону: делегация TLD .sh это прямо диверсия! пришлось упоминание своего скрипта как код оформлять, иначе считало это активной ссылкой)


              1. CaptainFlint
                22.04.2024 22:26
                +1

                Просто про смартфон автор ветки начал разговор, поэтому я и упомянул, что там будет не так удобно пользоваться консольной тулзой.

                А вообще я лично тоже терпеть не могу пользоваться смартфоном как MFA-устройством. Крайне раздражающая и неудобная концепция.


                1. dartraiden
                  22.04.2024 22:26

                  Крайне раздражающая и неудобная концепция.

                  Безопасность vs удобство, извечная дилемма.


        1. mm3
          22.04.2024 22:26

          Можно попробовать настроить на этом "телефоне" синхронизацию времени по GPS, была вроде такая фича некоторое время на андроиде, а если уже недоступна, то наверняка есть программы реализующие такой функционал.


        1. inkelyad
          22.04.2024 22:26
          +4

          Очевидно, у сберовских программистов своеобразные понятия о том, что такое "стандартная реализация" 

          Это не у них может быть. А у таблицы таймзон в какой-нибудь Java внутри телефона, которую забыли обновить. Потому что, скажем, некоторые варианты до сих пор думают, что в самарской таймзоне (если она вообще есть) времени есть переход на летнее время да еще и смещение не то, которое было. В результате в unixtime то самое текущее время, вводимое руками, неправильно пересчитывается.

          Проверяется легко - ставим таймзону, синхронизируем время по NTP (не ставим руками и не берем с сотовой сети - там оно правильное смещение умеет передавать) через WiFi и смотрим, а правильно ли часы телефона время показывают.

          Или по другому - поставить UTC зону, ввести UTC время, потом переставить зону, не трогая само время. И посмотреть показание часов/правильность кодов OTP.


          1. ThingCrimson Автор
            22.04.2024 22:26

            Кстати да, если время на устройстве выставляется местное, то возможны варианты с пересчётом в UTC при устаревшем tzdata — это Вы очень верно подметили!


    1. ThingCrimson Автор
      22.04.2024 22:26
      +2

      Воистину удивительные вещи могут сотворить одарённые люди при реализации хорошо документированных стандартов! Ведь в RFC 6238 явно прописано использовать UNIX time (Определяется как количество секунд, прошедших с полуночи (00:00:00 UTC) 1 января 1970 года (четверг)); да и целый раздел посвящён проблеме синхронизации, с рекомендацией:

      If the time step is 30 seconds as recommended, and the validator is set to only accept two time steps backward, then the maximum elapsed time drift would be around 89 seconds, i.e., 29 seconds in the calculated time step and 60 seconds for two backward time steps.


      1. Wesha
        22.04.2024 22:26
        +3

        Ведь в RFC 6238 явно прописано использовать UNIX time

        Хе, кожаные мешки уже который десяток лет костыляют "валидацию емейл-адреса" каждый в меру своего понимания (при том, что в RFC совсем другое написано), а Вы всё ещё на что-то надеетесь...


        1. ThingCrimson Автор
          22.04.2024 22:26

          Да, есть такое! Почитал Ваш перевод, полезная штука — и то, в RFC 3696 уже не упоминается UUCP bang notation (RFC 976) типа system!user@domain. Хорошо, если есть проверенные библиотеки (привет, supply chain attack!); а если делать самому ab ovo — то читать всю доступную документацию, включая лютое legacy.

          А надеюсь я так, pro forma… Но всегда приятно быть удивлённым!


  1. M_AJ
    22.04.2024 22:26

    взял USB-устройство попроще

    Хоть бы сказали какое.


    1. ThingCrimson Автор
      22.04.2024 22:26
      +2

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

      Это изделие ACS PocketKey от компании Advanced Card Systems Ltd. Форм-фактор USB Type-A (USB 2.0), криптография на ECC p256, поддерживает стандарты FIDO U2F и FIDO2 L1.


    1. dartraiden
      22.04.2024 22:26
      +1

      Устройств попроще на алике полно по запросу "FIDO2"

      До ответа автора я по фото даже подумал, что это что-то от KEY-ID, по внешнему виду очень похожи.


  1. Raegdan
    22.04.2024 22:26
    +1

    А ведь полностью аппаратный TOTP-токен тоже возможен. Пластина в формате банковской карты, только потолще. На борту eInk дисплей, всесистемный приемник GNSS для периодической коррекции локальных часов, и клавиатура с HEX набором. Буквы хекса вводят символы при вводе ключа, в остальных состояниях являются функциональными кнопками. Цифры всегда вводят цифры - ввод пин-кода при разблокировке и навигация. Питать это все от пары биосных батареек. Для дополнительной паранойи можно хранить базу в оперативке, питать ее через обрывную обмотку в стенках корпуса, и конструктивно обеспечить замену батареек только по очереди, для непрерывности питания.


    1. ThingCrimson Автор
      22.04.2024 22:26

      Да, возможен! В описанном Вами формате точно существовали аппартные генераторы HOTP; а впрочем вот нашёл и Feitian c200 TOTP:

      Feitian c200 в копусе I34
      Feitian c200 в копусе I34


      1. Raegdan
        22.04.2024 22:26

        Ну все же не совсем. Я имел в виду примерно так - вводим пин для разблокировки, видим меню:

        Меню
        01 Google
        02 Hotmail
        ....
        20 Facebook
        -------
        A: Prev page
        B: GNSS sync
        C: Lock session
        D: New entry
        E: Delete entry
        F: Next page
        

        Соответственно, вводим номер с клавы и сразу получаем соответствующий 2FA код, а хекс буквы служат функциональными клавишами. Сами собой они являются, если мы войдем в режим New entry и будем там вводить ключ. Название сервиса вводим с цифр по принципу SMS.

        P.S. Да и приема времени от GNSS я в спеке этого брелка не увидел.


        1. ThingCrimson Автор
          22.04.2024 22:26

          Скажу честно, глубоко в спецификации я не смотрел; время там каким-то образом всё же поддерживается более-менее точным; а вот что касается меню — очень может быть, что оно вообще для Одного-Единственного Самого Секретного Сервиса.

          В любом случае, устройства с CTAP1 / CTAP2 делают такие аппаратные HOTP / TOTP токены устаревшими. Чем запоминать на устройстве секреты от разных сервисов, чтобы потом использовать достаточно примитивную математику для получения хэша — лучше взять за основу современное ассиметричное шифрование на эллиптических кривых; секретный ключ выжжен в устройстве, публичный сообщается сервису при регистрации и запоминается им. И всё, при аутентификации сервис посылает челлендж, токен отвечает на него и подписывает ответ своим секретным ключом; сервис проверяет ответ и подпись — бинго!


          1. inkelyad
            22.04.2024 22:26

             секретный ключ выжжен в устройстве

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

            С другой стороны, выжеч прямо на фабрике и зашить в устройство можно пару десятков тысяч штук. Это всего ~300 килобайт для 128 битного ключа.

            И пускай устройство последовательно предлагает, когда генерацию просят.

            Но тут шуметь будут уже параноики-криптографы. Дескать, нет никакой гарантии, что фабрика эти ключики куда-нибудь не сохранила.


          1. Raegdan
            22.04.2024 22:26

            Ну это по сути обыкновенный USB-токен получается, с помощью которого бухгалтера логинятся в свои сбисы и диадоки. Тут загвоздка в том, что требуется двусторонний обмен между токеном и устройством, соответственно страдает или удобство, или универсальность, или дешевизна. А в чем несекурность TOTP, особенно если вовремя переходить на более современные криптопримитивы - не понимаю.


            1. inkelyad
              22.04.2024 22:26

              Ну это по сути обыкновенный USB-токен получается, с помощью которого бухгалтера логинятся в свои сбисы и диадоки. 

              Ну да. Я и написал, что не понимаю, почему не захотели воспользоваться всеми этими протоколами, а изобрели новый.

              С точки зрения использования - что так, что так втыкаешь какое-то устройство в USB (ну или то же самое по Bluetooth/NFC)

              Тут загвоздка в том, что требуется двусторонний обмен между токеном и устройством,

              В момент создания учетки - он всегда требуется чтобы seed в токен попал. Сканирование QR-это именно оно. Ну, если он не зашивается на заводе. Но если зашивается - то ключ/публичная часть ключа должна как-то в сервис попасть. Они достаточно длинные, чтобы руками было не набрать, даже если токен его покажет.

              А в чем несекурность TOTP, особенно если вовремя переходить на более современные криптопримитивы - не понимаю.

              Нет защиты от MitM при регистрации, например. Или что seed хранится и у тебя и на стороне сервера и может оттуда утечь.

              В более совершенных проколах над этим поработали. Особенно хорошо будет, если токен нормальным экраном обладает. Можно будет показать 'сайт example.com' хочет сгенерировать учетку, разрешить?

              А в TOTP возможен сценарий, когда в основном сервисе регистрируется промежуточный товарищ, а тебе, для инициализации генератора - предлагает свой seed.


        1. inkelyad
          22.04.2024 22:26
          +2

          Однако сейчас нужно хотеть уже не генератор OTP (ну устаревает оно), а устройство для работы с Passkeys/WebAuthn, интерфейсами PC/SC и прочими CCID-образными.

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

          ...И почему смартфоны, у которых USB, Bluetooth, NFC есть, аутентификатором по этим CCID образным интерфейсам работать не умеют.

          А у устройства, показывающего циферки есть, кажется, только одно преимущество - явный air gap и, соответственно, никакого специализированного интерфейса от того устройства, где оно применяется, не требуется.


          1. dartraiden
            22.04.2024 22:26

            ...И почему смартфоны, у которых USB, Bluetooth, NFC есть, аутентификатором по этим CCID образным интерфейсам работать не умеют.

            В смысле, не умеют? Например, можно с любого компьютера войти по пасскею, сохраненному на айфоне.

            https://support.apple.com/ru-ru/guide/iphone/iphf538ea8d0/ios

            https://fidoalliance.org/news-your-google-android-7-phone-is-now-a-fido2-security-key/


            1. inkelyad
              22.04.2024 22:26

              Это не тот сценарий. Точнее, не тот интерфейс. Это, судя по англоязычному описанию того же - новые Passkeys.

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

              А Passkeys с соседнего устройства, насколько я понимаю - хочет наличия на том самом устройстве Интернет соединения. В отличии от аппаратных токенов.


    1. xSVPx
      22.04.2024 22:26

      Он не "возможен" - это единственный разумный вариант. И подобные устройства раньше давали нормальные банки. Только они там не тотр использовали, а вообще одноразовый шифр-блокнот.

      Для тотр очевидно нужно устройство с вводом пина и выбором ключа. Ведь для разных сервисов хорошо бы разные ключи. И вот тут надо бы поискать. У меня руки не дошли пока :(

      Ввод пароля по нажатию клавиши это в целом неплохо(а поддерживает ли он много ключей?), но яб лучше с экрана набил, удобнее как по мне. С телефоном к примеру неудобно по usb втыкать итп.


      1. Raegdan
        22.04.2024 22:26

        Я выше расписал, как вижу примерную логику девайса https://habr.com/ru/articles/809569/#comment_26754969


      1. ThingCrimson Автор
        22.04.2024 22:26

        Позволю себе не согласиться! Чуть выше я написал, что HOTP / TOTP (как и простыни с OTP, пользовался такими в одном банке лет 15 назад) это уже вчерашний день. А современное состояние дел — использование ассиметричного шифрования, когда один токен с намертво прошитым секретным ключом ползволяет использовать множество сервисов (которые на стадии инициализации 2FA зипоминают у себя публичный ключ токена).


        1. xSVPx
          22.04.2024 22:26

          Ну т.е. перехватив один "ответ", скажем в хабр ты логинился, можно будет украсть все твои деньги из банков, с биржи итп :)?

          Прелестно.