Когда я решил избавиться от необходимости постоянно носить с собой смартфон, одной из проблем оказалась двухфакторная аутентификация (2FA, приложение Google Authenticator). Остаться без возможности авторизации на множестве сервисов было неприемлемо, нужна была альтернатива.

Беглый поиск вывел меня на утилиту oathtool: командная строка, POSIX, OSS — всё, как я люблю, проблема в принципе решена. Но, как и большинство CLI утилит, её удобно использовать в сочетании с другими утилитами, а для этого полезно написать скриптовую обвязку. Собственно этой обвязкой, а также опытом использования, я и решил поделиться.

Про 2FA вообще и TOTP в частности

Регистрация в системе при помощи пары логин / пароль — самый старый, самый распостранённый и, пожалуй, самый критикуемый способ аутентификации. Собственно к написанию статьи меня подтолкнула публикация Почему пароли безнадежно устарели и зачем ими до сих пор пользуются? и особенно комментарии к ней.

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

Давно родилась идея подкреплять аутентификацию по паролю чем-то другим. Из банковской сферы пришёл «ответ на контрольный вопрос», но по сути он был как второй пароль, слабый и долгоживущий. А вот одноразовые пароли (OTP) это уже было существенно лучше. Сперва их отправляли с помощью SMS или в виде hard copy (напечатанный список из десятка-другого кодов, по исчерпанию надо было получать новый) — это было не всегда удобно, не всегда безопасно, не всегда бесплатно.

Хорошей идеей оказалось генерировать OTP одновременно на стороне сервера и клиента на основании некоего общего секрета (shared secret) и постоянно увеличивающегося числа (например, счётчик попыток регистрации). Из этих двух сущностей однозначно составляли сообщение (message) и затем при помощи хеш-функции SHA-1 получали HMAC. Так появился HOTP (описан в RFC 4226, декабрь 2005 года).

У HOTP оказалось два несовершенства: возможна рассинхронизация счётчика (на стороне клиента генерацию могут вызывать чаще, чем было выполнено успешных аутентификаций, повторной синхронизации посвящён §7.4 RFC) и неограниченный срок жизни OTP (могло представлять угрозу при использовании фишинговых «прокладок»). И тогда было предложено расширение TOTP (описано в RFC 6238, май 2011 года).

В этом расширении в качестве постоянно увеличивающегося числа предложили взять текущее время UNIX time (количество секунд прошедших с 01.01.1970 00:00:00 UTC), делённое на длину интервала валидности OTP (по умолчанию 30 секунд). Таким образом, если часы на сервере и клиенте синхронизированы (несколько секунд туда-сюда роли не играют), то при одинаковом общем секрете сгенерированные значения TOTP совпадут — что и будет требуемым подтверждением аутентификации!

Постановка задачи

Разумеется, при наличии oathtool генерация TOTP возможна сразу же, напрямую:

$ oathtool -b -t SKEY

Но ключ инициализации лучше хранить зашифрованым и передавать не в командной строке, а через конвейер (pipe). В руководстве по oathtool есть рецепт, как это организовать с использованем GNU Privacy Guard (gpg):

$ gpg --decrypt --quiet ~/.my-totp-secret.asc | oathtool --totp -

На этом можно было бы и остановиться, но кроме необходимости запоминать / набирать много букв, есть ещё одна специфическая для TOTP особенность: при стандартном кванте времени 30 секунд можно запустить генерацию в такой момент, когда срок действия сгенерированого кода будет пара секунд, и можно не успеть выделить / скопировать / вставить / отправить его.

Поэтому я решил написать скрипт (назову его mytotp.sh) с таким функционалом:

  • mytotp.sh вывод названий всех добавленых сервисов

  • mytotp.sh SERVICE вывод TOTP для указанного сервиса с максимальным временем валидности

Уже в ходе написания статьи я хотел добавить mytotp.sh --help вывод подсказки по использованию и mytotp.sh --add SERVICE добавление ключа инициализации для SERVICE. Но вовремя вспомнил о принципе YAGNI и дал себе по рукам за попытку превратить простенький скрипт в Программный Продукт.

Предварительные требования

Собственно сама утилита oathtool (в зависимости от используемой ОС может быть установлена в составе пакета oathtool или oath-toolkit) и GNU Privacy Guard (gpg, скорее всего уже установлен). Для хранения ключей инициализации TOTP буду использовать ассиметричное шифрование GPG, так что нужна пара приватный / публичный ключи (можно использовать уже существующий, или сгенерировать новый, специально для TOTP).

Создание пары ключей для GPG специально для TOTP

Парольную фразу лучше поставить свою вместо Slozhnyj-parol, два пробела между $ и gpg не случайность — при установленной переменной окружения HISTCONTROL=ignoreboth строка не попадёт в историю.

$  gpg --yes --batch --passphrase 'Slozhnyj-parol' --quick-generate-key "My TOTP"

И для хранения всех ключей инициализации в одном месте нужно создать каталог:

$ mkdir -p ~/.config/mytotp && chmod 0700 ~/.config/mytotp

Реализация

Собственно говоря, сам скрипт очень тривиален, потому спрячу его под спойлер. Единственная изюминка — задержка с генерацией TOTP до ближайшей :00 или :30 секунды, чтобы полученный код максимально долго (все 30 секунд) был валиден.

Для интересующихся — код скрипта и ссылка на GitHub
#!/bin/bash
#
# Put TOTP key for service SERVID to GPG file crypted for 'My TOTP'
#  gpg -e -r 'My TOTP' > ~/.config/mytotp/SERVID.gpg

KEYDIR=~/.config/mytotp
KEYEXT=.gpg
SERVID=$1

if [ -z "${SERVID}" ] ; then
  echo -e "Usage: $0 SERVID\n\tSERVID is a service ID, abbreviated, w/o ext:"
  find ${KEYDIR}/*${KEYEXT} | sed -e 's/\/home.*\//  /; s/\.gpg//'
  exit 2
fi

if [ ! -f "${KEYDIR}/${SERVID}${KEYEXT}" ] ; then
  echo "No key for ${KEYDIR}/${SERVID}${KEYEXT}"
  exit 1
fi

SKEY=$(gpg -d --quiet "${KEYDIR}/${SERVID}${KEYEXT}")

NOWS=$(date +'%S')
WAIT=$((60 - NOWS))
if [ ${WAIT} -gt 30 ]; then
  WAIT=$((WAIT - 30))
fi
echo -n "Seconds :${NOWS} (wait ${WAIT}) ... "
sleep ${WAIT}

TOTP=$(echo "${SKEY}" | oathtool -b --totp - )

echo "${TOTP}"
OKEY="none"

exit 0

Я раньше всегда обходился SVN, но раз Git теперь «стильно модно молодёжно», то попробую соответствовать: репозиторий mytotp.

Использование (на примере GitHub)

Захожу на github.com, Account / Settings / Password and authentication / Enable two-factor authentication. Под QR-кодом нахожу и нажимаю “setup key”, копирую строку “Your two-factor secret” (на всякий случай сохраняю её и в парольном менеджере, в карточке логина на GitHub). Выполняю в консоли:

$ gpg -e -r 'My TOTP' > ~/.config/mytotp/github.gpg
XXXXXXXXXXXXXXXX	(нажимаю Ctrl+V)
(Ctrl+D)

После запускаю mytotp.sh github, ввожу парольную фразу от ключа, жду появления 6-значного кода, ввожу его на сайте — 2FA активирован и проверен, без смартфона!

Генерация TOTP: было и стало
Генерация TOTP: было и стало

Заключение

Писал для себя, потому что нужно было. Решил поделиться, вдруг ещё кому-то полезным окажется. В планах возможно учесть варианты, когда для какого-то сервиса количество цифр не 6, и/или HMAC функция не SHA-1. Но пока у меня всё работает, так что YAGNI.

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

Добрый совет всем (даже кто не планирует отказываться от смартфона и радостно сканирует QR-коды): при включении 2FA на сервисе сохраняйте также и текстовый ключ инициализации! Когда надумаете на другое приложение переходить — пригодится!

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


  1. MonkAlex
    26.03.2024 11:08
    +21

    сохраняйте также и текстовый ключ инициализации

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

    А тогда уж можно использовать KeePassXC, в котором есть и возможность работать с TOTP.


    1. ThingCrimson Автор
      26.03.2024 11:08
      +1

      Да, Вы верно подметили! Я просто чуть выше написал про «сохраняю её и в парольном менеджере» и не продублировал это в заключении.

      Что касается KeePassXC, то он хорош, но не когда у тебя только SSH до сервера / VDS. Потому я и держу также решения для командной строки.


      1. BcTpe4HbIu
        26.03.2024 11:08
        +2

        Password-store + otp плагин делают тоже самое, теми же инструментами.


        1. ogost
          26.03.2024 11:08

          Более того, у password-store куча плагинов, реализаций и интерфейсов, с плагинами умеет автозаполнять куда угодно, хоть в браузер, хоть в командную строку и вообще очень удобен в использовании.


        1. ThingCrimson Автор
          26.03.2024 11:08
          +1

          Да, всё так! Чуть ниже я написал про pass:

          при первом знакомстве он как раз показался мне Программным Продуктом на BASH (когда проще написать что-то коротенькое «под себя», чем разбираться с развесистым комбайном).

          Имеет ли право на существование самопальный простой и легко обозримый велосипед? Я считаю, что да; Вы можете быть со мной несогласны…


    1. aldekotan
      26.03.2024 11:08

      Благодарю за упоминание KeePass) Не ожидал, что для подобных операций можно использовать и простое приложение на пк. Но невольно задаюсь вопросом, в чём тогда смысл подобной авторизации, если телефон не обязателен.


      1. micronull
        26.03.2024 11:08
        +2

        Второй фактор защиты не обязывает наличие телефона или иного аппаратного средства.

        Смысл в одноразовых кодах. Пароль можно взломать элементарным перебором, а одноразовые коды нет.


        1. ThingCrimson Автор
          26.03.2024 11:08

          Именно так! Особенно если хранить пароль для входа и ключ TOTP в разных базах (как здесь мне уже справедливо заметили, и вроде в документации на KeePassXC есть соответствующие рекомендации).


        1. MiyuHogosha
          26.03.2024 11:08

          Одноразка на бумажке тоже легко обходилась -да и утекать она может

          Только теперь рассылать СМС или звонки скодами обходится в три дорога. Даже почта России и ФНС перешла с приложения. Результат - каждый просто обязан иметь 100500 установленных приложений и без смартфона человек практически превращается в негражданина


          1. xSVPx
            26.03.2024 11:08

            Нормальные скретч карты даже не знаю как могут утекать. И как их обходить.

            Поделитесь кейсами?


      1. MonkAlex
        26.03.2024 11:08

        Хороший вопрос, у меня нет на него ответа. У меня пароли и TOTP в одной базе кипаса, так что вместе утекут, если что.


        1. shares-caisson
          26.03.2024 11:08
          +1

          Защищает от утечки пароля любым другим путём, кроме похищения базы паролей.


      1. xSVPx
        26.03.2024 11:08
        +4

        Ни в чем. Очень слабая дополнительная защита.

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

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

        Конечно совсем хорошо, когда 2фа демонстрирует владение чем либо как второй фактор, т.е. вам надо что-то знать и чем-то владеть. Но, к сожалению, никто не озабочен безопасностью клиентов. Ещё лет десять назад аппаратные одноразовые шифр блокноты были обычной штукой, сейчас их заменили смс :((.


  1. aborouhin
    26.03.2024 11:08
    +4

    1. Не проще ли взять любой парольный менеджер с поддержкой TOTP (у меня Bitwarden/Vaultwarden на своём сервере, любители держать всё локально могут и Keepass взять)? (P.S. комментом выше меня опередили, пока я свой набирал :) Заодно автозаполнение / автокопирование в буфер кодов будет, удобно.

    2. С Microsoft у меня всё тоже работает, специально скормил oathtool сохранённый в Bitwarden секрет для учётки MS - он спокойно выдал правильный код. Вот у Яндекса свой велосипед, да...


    1. ThingCrimson Автор
      26.03.2024 11:08

      «К одной вершине ведут сто путей», можно и так! Но я по возможности стараюсь пользоваться CLI утилитами, так уж сложилось…

      А что касается MS Authenticator надо будет ещё поковырять, у меня пока oathtool ругается, мол неверный формат секрета. А вот если пропустить его через другой аутентификатор, может и получится — спасибо за наводку!


      1. aborouhin
        26.03.2024 11:08
        +2

        Так MS совершенно прекрасно умеет использовать не только свой Authenticator (ещё раз камень в огород Яндекса), но и гугловский и любой другой сторонний. Точно так же предлагает QR-код или текстовый секрет при настройке. Родное их приложение добавляет подтверждение входа без кода, просто всплывающим сообщением на смартфоне, а вот собственно TOTP-часть вполне стандартная. Если, конечно, ничего не поменяли в последние годы, уже после того как я себе настраивал.


        1. ThingCrimson Автор
          26.03.2024 11:08

          Ещё раз спасибо, попробую отключить и затем снова включить 2FA на хотмейле, может это я где-то ошибся, когда строку инициализации сохранял!


          1. inkelyad
            26.03.2024 11:08
            +1

            Ещё раз спасибо, попробую отключить и затем снова включить 2FA на хотмейле,

            Там сейчас есть некая проблема с тем, чтобы выбрать именно тот способ, который 'обычный' TOTP - оно несколько неочевидно и запрятано, если я правильно помню.

            По умолчанию все уводит именно в подтверждение всплывающим сообщением. Где тоже, кстати, несколько дальнейших сценариев есть. Где-то предлагают выбрать нужное число из трех. Где-то предлагают сравнить какой-то ID запроса что на странице видно и что в авторизаторе показывается. Где-то можно (если связи нет?) ввести в конце концов (довольно длинное) число. MS что-то там со всем этим экспериментировало.


      1. CaptainFlint
        26.03.2024 11:08
        +1

        Для Microsoft надо отдельно включать TOTP-аутентификацию, и потом каждый раз, когда запрашивается 2FA, необходимо тыкать ссылочку "я не могу прямо ща задействовать MS, дай мне другой способ". А сам MS Authenticator — не TOTP, хотя бы потому, что он двунаправленный: показывает код на сайте и требует его ввести в аутентификаторе, а не наоборот.


        1. ThingCrimson Автор
          26.03.2024 11:08

          Ох затейники! Постараюсь сегодня проверить, самому интеренсно стало…


      1. Didimus
        26.03.2024 11:08

        Мс аутентификатор постоянно разлогинивается, и очень часто не удаётся обратно залогиниться. Так себе утилита для восстановления доступов.

        Очень бы хотелось наконец получить стандарт на железные аутентификаторы, и чтобы они были недорогие и надёжные


    1. AndrewVT
      26.03.2024 11:08

      Вполне себе яндекс работает с Google Authenticator.
      Он конечно при настройке пишет только про их приложение, но GA спокойно читает qr-код и потом дает рабочие пароли


    1. xDamneDx
      26.03.2024 11:08
      +1

      Как выше писали не защищает от кражи базы. В идеале 2фа должно защищать от кражи одной из бд паролей.


  1. 13werwolf13
    26.03.2024 11:08
    +4

    $(oathtool --base32 --totp $(/usr/bin/kwallet-query -f XXX -r YYY kdewallet))

    я просто оставлю это здесь

    алсо я солидарен с ораторами выше, сам юзаю такую схему: KeePassXC с двумя базами, в одной пароли в другой секреты TOTP, естественно хранящиеся по разному и бекапящиейся в разные места


  1. l0ser140
    26.03.2024 11:08
    +4

    Из двухфакторной авторизации получается что-то странное.

    Фактор владения и фактор знания где-то перемешиваются в вашем менеджере паролей, где наверняка хранятся gpg ключи и пароли от сайтов.


    1. ThingCrimson Автор
      26.03.2024 11:08
      +2

      Да, Вы правы! Надо будет перенести секреты TOTP в другую базу, это я что-то сильно угол срезал…

      (в сторону) Вот почему полезно публиковать свои мысли в сообществе умных людей!


      1. l0ser140
        26.03.2024 11:08
        +2

        По идее, чтобы следовать принципу 2FA база паролей и база TOTP токенов не должны быть на одном устройстве.

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

        В общем это конечно добавляет безопасности, но противоречит 2FA.


        1. aborouhin
          26.03.2024 11:08
          +1

          2FA всё-таки не про разные устройства, а про разные факторы. Но в текущем разнообразии способов хранить пароли всё это очень условно.

          Даже без TOTP менеджер паролей уже даёт нам два фактора - владение базой паролей и знание мастер-пароля для её расшифровки (второй, правда, ослаблен, т.к. мастер-пароль один на всех, но тем не менее). Если доступ к менеджеру паролей удалённый и сам защищён TOTP - опять другая картинка, которая не укладывается в обычную схему. А если база менеджера у нас на отдельной флэшке с аппаратным шифрованием и своим паролем? В общем, IMHO, в каждом случае надо смотреть на конкретные сценарии атаки и насколько та или иная схема в них помогает.


        1. CaptainFlint
          26.03.2024 11:08
          +2

          На самом деле не противоречит. Факторы знания и владения по-прежнему остаются разными. Если кто-то подсмотрел пароль (даже пароль от базы), он будет ему бесполезен без самой базы, а для этого нужен уже физический доступ к устройству, да ещё чтобы оно было разблокировано. И наоборот, если стырили зашифрованную базу, но неизвестен пароль, она бесполезна.

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


        1. ThingCrimson Автор
          26.03.2024 11:08

          Да, полностью соответствующее принципу 2FA решение — аппаратный токен с защитой по пину. Но тут уж принцип разумной достаточности говорит, что 2FA с Google Authenticator / oathtool / etc всяко лучше, чем отсутствие 2FA вообще.


  1. pvzh
    26.03.2024 11:08
    +1

    сохраняйте также и текстовый ключ инициализации

    А где сохранять то? В менеджере паролей? Если применять опенсорсные KeePassXC и KeePassDX то он (секрет) и так там хранится, применяется для генерации кода и его можно всегда посмотреть.


    1. ThingCrimson Автор
      26.03.2024 11:08

      В моём случае ключ иницализации сохраняется в ~/.config/mytotp/SERVICE.gpg, ну и в KeePass Touch на айфоне. Но и вариант с KeePassXC хорош (если, как тут верно отметили, разделять базы с паролями и 2FA).


  1. CaptainFlint
    26.03.2024 11:08
    +5

    Насчёт ухода от границ 30-секундных интервалов: где-то мне попадалась информация, что это обычно учитывают и сервер принимает не только OTP-код для текущего интервала, но и коды от предыдущего и будущего интервалов. Таким образом допускается как небольшой рассинхрон времени (когда код сгенерирован от будущего интервала), так и то самое "сгенерил на 29-й секунде и не успел вставить".


    1. ThingCrimson Автор
      26.03.2024 11:08

      Да, про это написано в §6 RFC6238:

      Because of possible clock drifts between a client and a validation server, we RECOMMEND that the validator be set with a specific limit to the number of time steps a prover can be "out of synch" before being rejected.

      Но практика показывает, что далеко не всегда рекомендации стандартов соблюдают в точности, я вот решил перестраховаться.


  1. Abyss777
    26.03.2024 11:08

    Подскажите, а в разблокированный KeePassXC можно как-то из консоли за паролем сходить?
    Обычные команды требуют пароль от базы, надо бы как-то типа как интеграция с браузерами работает.


    1. Zrgk
      26.03.2024 11:08

      kpcli


      1. Abyss777
        26.03.2024 11:08

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

        Видимо через HTTP придётся ломиться https://pypi.org/project/keepasshttp/


    1. dartraiden
      26.03.2024 11:08
      +2

      Можно AutoType использовать, чтобы KeePass по хоткею ввёл код в нужное окно.

      https://keepass.info/help/base/placeholders.html

      https://keepass.info/help/base/autotype.html


  1. splitfire
    26.03.2024 11:08

    Всё же, как ни стараюсь, не улавливаю суть такой реализации 2FA. Понимаю, если второй фактор биометрия; если второй фактор обладание(тут и аппаратные ключи и сим-карта и т.д.). Но в данной-то схеме: у нас был один пароль, знание этого пароля обеспечивало аутентификацию. Теперь у нас два пароля -- основной и ключ инициализации TOTP, знание которых обепечивает аутентификацию. Да, это имело бы смысл, если бы пароли передавались в открытом виде и перехват постоянно и непредсказуемо меняющегося TOTP мало бы помог. Но в реальности то пароли передаются по защищенному каналу. И чем в этом случае знание двух паролей принципиально отличается от знания одного пароля, я не догоняю...


    1. aborouhin
      26.03.2024 11:08
      +4

      1. Защищённый канал не панацея от перехвата.

      2. TOTP-код не записать на стикере, висящем на мониторе.

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

      4. Наличие TOTP не позволяет просто подсмотреть (вживую или через камеру наблюдения), как пароль вводится с клавиатуры (впрочем, парольный менеджер эту проблему решает и без TOTP)

      5. Утечка со стороны удалённого сервиса может, теоретически, раскрыть пароль (если они там плейнтекстом хранятся), но не раскрыть TOTP (для чего, вероятно, используется сторонняя библиотека, разработчики которой поумнее).

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

      P.S. Ну и если строго про терминологию - пароль (без парольного менеджера) ещё может быть фактором знания, а вот TOTP-секрет - это 100% фактор обладания (файлом / приложением / базой / устройством).


      1. splitfire
        26.03.2024 11:08

        1-5 все это корректно и для стандартных паролей. Их тоже не нужно писать на листочке хранить плэйнтекстом и тд.

        А про терминологию, да с чего же это TOTP-секрет -- это фактор обладания, если сам по себе он набор символов, а преобразовать его в рабочую форму можно кучей приложений, которые свободно скачиваются на любой телефон/компьютер, "без регистрации и СМС"? По этой логике и обычный пароль, если он записан на листочке, тоже фактор обладания.


        1. aborouhin
          26.03.2024 11:08
          +2

          Их тоже не нужно писать на листочке хранить плэйнтекстом и тд.

          Только можно долго, упорно и бесполезно объяснять это пользователям, а можно внедрить обязательный TOTP и снять хотя бы какие-то риски (ещё, кстати, забыл ситуацию "поделиться своим паролем с коллегой, очень срочно надо", в результате которой пароль неконтролируемо расходится по рукам). Ну а п. 4-5 вообще не про это, тут никто не застрахован, даже если для одного себя любимого настраиваешь.

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

          Да, конечно, если мы его не помним, а каждый раз смотрим на листочек. Или пароль в базе парольного менеджера, не важно. Фактор знания - то, что у нас в голове и что мы можем рассказать. Фактор обладания - то, что мы можем потерять / у нас могут украсть или отобрать. Два разных устройства и листочек с паролем - это три фактора обладания, и это нам вообще не поможет, если все лежат в одной сумке, которую украли или изъяли.

          Проблема с фактором знания в том, что он плохо масштабируется и никак не бекапится, поэтому мы и заменяем фактор знания на фактор обладания (плюс ослабленный фактор знания мастер-пароля), используя парольные менеджеры. И не так уж это плохо.

          Ну а в случае, если у нас не физический ключ / локальный файл или пароль в голове, а доступ к облачному хранилищу / приложению - тут вообще сам чёрт ногу сломит, где знание, а где обладание :) Так что лучше, мне кажется, не привязываться к терминам, а реальные сценарии атак моделировать, они тоже у всех разные.


          1. inkelyad
            26.03.2024 11:08

            Фактор обладания - то, что мы можем потерять / у нас могут украсть или отобрать.

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

            OTP в том виде, как оно обычно используется - этому не очень соответствует, потому что воспользоваться можно, где-то перехватив seed для генератора (вытащив из бакапа базы данных генератра) и им воспользовавшись. (А тот генератор, что у человека, так у него и остается - его никто не крал).

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

            Именно поэтому, я подозреваю, первые модели Google Authenticator бакапиться не умели - потому что seed лежал внутри защищенной части чипа, код считался там же и вытащить все наружу для целей резервного копирования by design невозможно было.

            И, кстати, если базы данных паролей крадут (и поэтому все твердят 'солите и хешируйте пароли при хранении на стороне сервера'), то с тем же успехом могут украсть (заодно с паролями) и базу seed-ов для OTP, с которым, вроде, это не получается.


            1. aborouhin
              26.03.2024 11:08
              +2

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

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

              (А тот генератор, что у человека, так у него и остается - его никто не крал).

              Ну ОК, добавим "или скопировав" :) Ключевой файл на флэшке, полный бекап телефона с Google Authenticator - всё это можно скопировать. Но чтобы скопировать - надо получить доступ. А чтобы узнать фактор знания - надо заставить / обмануть живого человека.

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

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

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

              с тем же успехом могут украсть (заодно с паролями) и базу seed-ов для OTP, с которым, вроде, это не получается.

              Моя надежда на то, что риск этого меньше, как я написал выше, основана на том, что если хранение паролей криворукий разработчик мог реализовать сам, то для TOTP он, вероятно, использовал стороннюю библиотеку, а то и сторонний сервис :)


              1. inkelyad
                26.03.2024 11:08

                Да. Поэтому листочек с паролем, который мы ещё и наизусть помним, - это фактор владения ИЛИ обладания.

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

                Что очевидно, не верно - можно воспользоваться этим фактором, набрав пароль из головы, (а не демонстрируя этот листочек какуму-то интерфейсу "вот оно, у меня в руках")

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

                Тут терминология (ее трактовка) отличается. Фактор обладания - это значит, что если ключевой артефакт у нас в руках и мы его видим (и он выключен, т.е. с окружающим миром не взаимодействует)- то это значит, что никто нигде и никак в сервис данным путем входа не зайдет. Т.е. защиты артефакта от посторонних гарантированно достаточно, чтобы эти посторонние в сервис не попали.

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

                В случае с листочком с паролем - это, еще раз, не так. Набрал пароль по памяти - и готово. Листочек (которым мы уже не владеем - он съеден) не понадобился.

                В подавляющем большинстве случаев невозможность сделать бекап влечёт куда более тяжёлые последствия

                Банковские карты с чипом, которые гораздо больше подходят под фактор обладания - вполне не копируются (штатными способами) и не бакапятся. Ничего, как-то живем.


                1. aborouhin
                  26.03.2024 11:08
                  +2

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

                  По поводу копируемости - не отрицая её важности для планирования защиты, всё же считаю, что это вторичный критерий, на классификацию фактора сам по себе не влияющий. Довольно странно было бы считать, скажем, ключ ЭЦП на копируемом токене фактором знания (где тут знание вообще?), а на некопируемом - обладания (а на официально не копируемом, но есть народные средства, как? а если средства есть только у производителя токена?) Так что копируемость влияет на "силу" фактора обладания, но не меняет сам тип этого фактора. По крайней мере, это моё глубокое убеждение исходя из общей логики, глубоко в теорию не погружался.

                  Банковские карты с чипом, которые гораздо больше подходят под фактор обладания - вполне не копируются (штатными способами) и не бакапятся. Ничего, как-то живем.

                  Вот после появления виртуальных банковских карт, которые можно выпустить из приложения банка в любой точке мира, стало как-то ещё "ничего". А когда у меня лет 10 назад во Франции банкомат российскую карточку съел и не захотел отдавать - было крайне неприятно :) (это всё без корректировок на текущие печальные реалии, само собой, сейчас, как говорится, нам бы те проблемы...)

                  Тут, конечно, речь не про копирование, а про восстановление доступа, но это вопросы взаимосвязанные. По сути, любая процедура восстановления доступа - это просто дополнительный альтернативный фактор или набор факторов (и это тоже надо учитывать, а часто забывают).


                  1. inkelyad
                    26.03.2024 11:08
                    +1

                    Вот после появления виртуальных банковских карт, которые можно выпустить из приложения банка в любой точке мира, стало как-то ещё "ничего".

                    Только они не копируют существующую, а выпускаются как новый (и другой) артефакт доступа. И это правильно, в общем-то.

                    Уже где-то объяснял разницу. Она в том, что отдельные артефакты можно лишать ключевого статуса по отдельности. (Физически уничтожили банковскую карту или закрыли виртуальную - а вторая продолжает работать). Копии же лишаются своего статуса одновременно. Сказал в личном кабинете сервиса "я телефон с этим генератором потерял - отключи его" -- и уже никакой копией (в том числе старательно сохраняемым бакапом, что дома в сейфе лежит) воспользоваться не можешь.


                    1. MiyuHogosha
                      26.03.2024 11:08

                      Есть системы где уничтожение артефакта ведёт к полной потере данных. Хранилища ключей часто делались на этом принципе. Другой пример. -файлообменник Mega


                1. LF28
                  26.03.2024 11:08
                  +1

                  Что очевидно, не верно - можно воспользоваться этим фактором, набрав
                  пароль из головы, (а не демонстрируя этот листочек какуму-то интерфейсу
                  "вот оно, у меня в руках")

                  Значит это плохой пароль только и всего. Нормальный пароль невозможно запомнить если вы не какой-то уникальный случай в природе человека.


                  1. ThingCrimson Автор
                    26.03.2024 11:08
                    +1

                    Я всё же сфомулировал чуть менее категорично: нормальный пароль невозможно гарантировано запомнить в долгосрочной перспективе (с учётом отпусков, проблем со хдоровьем и т.п.) То есть, всё равно его обязательно записывать тем или иным способом.

                    А так-то у меня ежедневно «в пальцах» несколько десятков достаточно сильных паролей. Но стоит недельку хотя бы не работать — и приходится освежать память.


                  1. UranusExplorer
                    26.03.2024 11:08

                    Нормальный пароль невозможно запомнить если вы не какой-то уникальный случай в природе человека.

                    ну как сказать


                    1. inkelyad
                      26.03.2024 11:08

                      Проблема только с придумыванием.

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

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


          1. MiyuHogosha
            26.03.2024 11:08

            Парольная база - это листочек с паролями записанными спец.чернилами.


      1. 0x131315
        26.03.2024 11:08
        +4

        У TOTP есть еще одно значимое преимущество, как у второго фактора: полная независимость от чего-либо. Работает идеально, чего не скажешь о других вторых факторах. Многие сервисы используют в качестве второго фактора смс или email, но сим-карты и почтовые ящики имеют свойство устаревать, и дарить пользователям проблемы на ровном месте, а TOTP просто продолжает работать.


        1. micronull
          26.03.2024 11:08
          +3

          сим-карты и почтовые ящики имеют свойство устаревать

          Ещё sms перехватывается.


  1. unreal_undead2
    26.03.2024 11:08

    Использование (на примере GitHub)

    А с банками сработает?


    1. ThingCrimson Автор
      26.03.2024 11:08

      Если с банком работает Google Authenticator, то на 99% сработает и предложенная схема. Надо только ключ инициализации иметь (получить при включении 2FA, обычно где-то рядом с QR-кодом есть ссылка типа «мы люди дремучие, картинок не понимаем, дайте нам буковками!»).

      А вот если 2FA уже включена и QR скормлен gAuth, тут я не уверен, что изначальный ключ выцепить можно. Впрочем, может у кого-то есть опыт подобного?


      1. unreal_undead2
        26.03.2024 11:08
        +2

        Если с банком работает Google Authenticator

        У нас такие есть?


        1. ThingCrimson Автор
          26.03.2024 11:08

          «Чтоб да, так нет!», ну то есть которые я знаю, те всё больше полагаются в качестве второго фактора аутентификации на СМС / Viber, или даже голосовой звонок (варианты: «нажмите 1 если это вы логинитесь» или «введите 4 последние цифры номера, с которого мы вас вызываем»).


          1. unreal_undead2
            26.03.2024 11:08

            Ну то есть применимость статьи сильно ограничена, лично я 2FA регулярно пользуюсь только для входа в банковские ЛК.


      1. CaptainFlint
        26.03.2024 11:08
        +3

        Если есть QR, необязательно его скармливать аутентификатору, можно просто расшифровать его обычной декодилкой и вытащить секретный ключ из текста. Вот если уже скормили и страницу закрыли, то сложнее. Хотя, кажется, в gauth добавили возможность экспорта куда угодно, а не только в другой gauth. Во всяком случае, что-то подобное я с ним уже делал, но детали уже забылись.


  1. kasiopei
    26.03.2024 11:08
    +2

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


    1. ThingCrimson Автор
      26.03.2024 11:08

      Думаю потому, что он сложнее / дороже (аппаратный токен). Ну и к реализации защиты тоже могут быть вопросы (если это не open source) — помню была история с «аппаратно защищёнными флешками», которые открывались на раз.


    1. shares-caisson
      26.03.2024 11:08

      Внедряют, только теперь это называется passkeys.


      1. inkelyad
        26.03.2024 11:08

        Так там же второй фактор где-то по дороге, по сути, потерялся? Все отдали на усмотрение хранилища этих самых ключиков.


        1. shares-caisson
          26.03.2024 11:08
          +1

          Так два фактора, это не какое-то незыблимое предписание, просто метод разделения рисков. Каждый из факторов, это (если посмотреть из первых принципов) просто некий набор секретных байтов, из которых часть ("пароль") хранится как попало неквалифицированным пользователем, а часть ("приватный ключ" или "общий секрет TOTP" или "генератор одноразовых кодов для СМС") хранится аккуратно и никаким недоверенным системам не предъявляется.

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


          1. inkelyad
            26.03.2024 11:08
            +1

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

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

            4.6

            ...

            No Bluetooth, Pure Internet: It is important to note that in this QR code-based passkey cross-platform authentication (hybrid transport), Bluetooth is not involved in the authentication and data exchange. This process relies entirely on an Internet connection for the transmission of encrypted data between the devices and the server.


            1. shares-caisson
              26.03.2024 11:08
              +1

              Каждый анализирует свои риски сам и может выбирать из предложенных методов, какой ему по душе. Passkey -- хороший компромисс, потому что если девайс пользователя поимели так, чтобы вытащить ключи -- то ему уже ничего не поможет, но современный обновлённый телефон поиметь -- это ещё постараться надо, проще компьютер, на котором все эти пароли вводятся похакать.

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

              Хардварные ключи -- хороший вариант, но геморой полный с тем, чтобы энролить минимум два ключа -- не получится один бэкапный бросить в сейф и забыть про него, всё время надо под рукой иметь, чтобы регистрироваться.

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


  1. LonFas
    26.03.2024 11:08
    +2

    А что мешает использовать https://habr.com/ru/articles/479540/?


    1. ThingCrimson Автор
      26.03.2024 11:08

      Спасибо за полезную ссылку! Про GNU pass я знал, но при первом знакомстве он как раз показался мне Программным Продуктом на BASH (когда проще написать что-то коротенькое «под себя», чем разбираться с развесистым комбайном).

      А так ничто не мешает, прекрасно что есть разные варианты решения для TOTP без смартфона! И ещё раз спасибо, что напомнили про passwordstore.org.


  1. adrozhzhov
    26.03.2024 11:08
    +4

    Про перенос записи из гугл-auth в любое другое приложение умеющее TOTP сегодня мини инструкцию писал. Скопирую сюда

    Вдруг захотелось заходить по 2fa без присутствия телефона. А код для генерации ключа не сохранял. Но можно сделать так:

    1. Заходим в гугло-аутинфикатор. Там есть "Экспорт" в QR код. Сохраняем код

    2. Распознаём код, который должен получится как url вида

    otpauth-migration://offline?data=ChkKCka3zvv%2B7zm9IQgSBXRlc3QxIAEoATACEAEYASAAKKXnpoD6%2F%2F%2F%2F%2FwE%3D

    Скачиваем с гитхаба парсер для этого дела

    https://github.com/qistoph/otp_export

    Читаем ридми (надо поставить пару пакетов) и запускаем как сказано

    python parse.py "otpauth-migration://offline?data=ChkKCka3zvv%2B7zm9IQgSBXRlc3QxIAEoATACEAEYASAAKKXnpoD6%2F%2F%2F%2F%2FwE%3D"
    version: 1
    batch_size: 1
    batch_index: 0
    batch_id: -1609976923
    otp_parameters:
      otpauth://totp/:test1?secret=I234567654432III&issuer=&algorithm=sha1&digits=6&counter=0
      secret: b'I234567654432III'
      name: test1
      issuer:
      algorithm: SHA1
      digits: SIX
      type: TOTP
      counter: 0
    

    Получили нужный код!
    Теперь его можно добавить локально в KeePassXC, оно умеет из коробки TOTP


    1. ThingCrimson Автор
      26.03.2024 11:08

      Супер! Вот этой информации и не хватало, чтобы гарантировано подружить с oathtool любой сервис (секрет в приведённом к стандартному base32 виде, алгоритм HMAC ну и количество цифр в генерируемом коде).

      Спасибо огромное что поделились!


  1. UnknownErrror
    26.03.2024 11:08
    +1

    Бонус: В oathtool можно передать в аргументы -w 1 что сгенерирует 2 кода - текущий и следующий


    1. ThingCrimson Автор
      26.03.2024 11:08

      Да, можно и больше указать (-w X для текущего 30-секундного слота и для X последующих):

      You may generate several TOTPs by specifying the --window parameter, similar to how it works for HOTP. The OTPs generated here will be for the initial time (normally current time) and then each following time step (e.g., 30 second window).

      Но я решил пойти на трюк с выравниванием генерации на :00 или :30 секундах, чтобы не запутаться.


  1. NickWinter
    26.03.2024 11:08
    +2

    Мне кажется, что приложение с кодами выносят на отдельное устройство в том числе ради безопасности


    1. ThingCrimson Автор
      26.03.2024 11:08

      Тут уже в комментариях обсудили эту философскую проблему (включая с тонкостями между «знать» и «владеть»). Но реальный мир таков, что 2FA в любом виде повышает безопасность, по сравнению с голым паролем.


      1. igors
        26.03.2024 11:08
        +1

        К сожалению, Вам верно указывают, что ввод пароля и выдача 2FA на одном устройстве, а тем более хранение 2FA-секрета внутри парольного менеджера это дизайн-профанация 2FA. Компроментация пользовательского терминала это самое вероятное, что может произойти, особенно учитывая фундаментальные проблемы безопасности современных CPU и обилие дырок в Windows, которым, как я понял, Вы пользуетесь.


        1. ThingCrimson Автор
          26.03.2024 11:08

          Я согласен с Вами, ввод пароля и выдача 2FA на одном устройстве существенно ослабляет безопасность, по сравнению с модельной реализацией (про храненение секрета в том же месте, что и пароль — однозначно косяк, уже так не делаю; с другой стороны, чуть ниже предлагают вообще в облачном iCloud Keychain всё хранить, удобно же!)

          Но как бы там ни было, в рассматриваемой мною модели угроз пароль + TOTP лучше чем просто пароль. А постояно иметь при себе лопату смартфона я устал… Для значимых сервисов я могу уйти от выдачи 2FA на том же устройстве, что и ввод пароля (работая с дектопом использовать ноутбук для SSH на сервер, где mytotp.sh живёт).

          Что касается Вашего захода с козырей про фундаментальные проблемы безопасности, то тут всё грустно. Если лет 30 назад шутили, что для Истинно Безопасной Системы надо сперва собрать свой компилятор (после аудита исходников, разумеется), потом им собрать ОС и утилиты — а сейчас, получается, сперва нужно свой процессор сделать (или хотя бы микрокод для него).


          1. igors
            26.03.2024 11:08
            +2

            Козыри ближе чем кажутся - чтение одного окна браузера из другого уже было успешно продемонстрировано на примере макоси, и проблема там не в макоси. Второй фактор должен быть на другом устройстве. У меня это Yubikey для большинства сервисов, но к сожалению он теперь стоит как крыло самолёта, а их надо два - у них конечный счётчик выдаваемых кодов, иногда они сбрасываются или ломаются.


  1. HabrSpar
    26.03.2024 11:08
    +1

    У автора, кажется, MacOS, и почему-то нет упоминания, что в iCloud Keychain (встроенный менеджер паролей Apple-аккаунта) с недавних времён можно добавить и 2FA авторизацию (не говорю уже о PassKey). Вбиваешь 1 раз в менеджер и потом одним кликом вбиваешь пароль и 2FA на всех устройствах Apple.

    Как настроить: https://appleinsider.com/inside/icloud/tips/how-to-set-up-two-factor-authentication-in-icloud-keychain/amp/


    1. ThingCrimson Автор
      26.03.2024 11:08

      Да, у меня MacOS 10.13, но это дома. На работе Windows 7; зато отовсюду есть SSH до кучи серверов / виртуалок. Так что выбор очевиден…

      А что касается iCloud Keychain, то при всём возможном уважении к фирме Apple (да не упадут её продажи ныне и присно и во веки веков), я не помещу туда ни одного значимого пароля (а вот для веб-сайтов магазинов и т.п. оно очень годится).