После публикации статьи «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 без смартфона»!
Работает со всеми моими сервисами (думаю, в 2024 году большинство веб-сервисов поддерживают CTAP); под Windows (7 / 10), MacOS (10.13+), Linux (Mint 21); с актуальными версиями FireFox и Safari (уверен, с Chrome тоже работать будет). Если не устанавливать свой PIN на токен (чистый фактор владения), то вообще ничего с ним делать не нужно, помимо:
Регистрация: зашли на сервис, выбрали настройку 2FA, аппаратный ключ; когда попросят — коснулись кнопки на ключе
Использование: зашли на сервис, увидели приглашение коснуться кнопки на ключе, коснулись — аутентификация выполнена
Из недостатков (кроме необходимости заплатить живые деньги): при поломке / пропаже токена остаёмся без 2FA. В Apple даже предлагают при активации 2FA использовать два разных токена; но вполне можно обойтись схемой «токен + TOTP», чем я и воспользовался.
Заключение
Итак, обозначенная задача решена мною теперь уже двумя способами: совершенным (но за деньги и не копируется) и чуть попроще (но бесплатно и подлежит резервному копированию).
Хочу поблагодарить всех участников дискуссии, которые не были упомянуты выше, за ваши высказанные мнения и замечания; а также уважаемую @Exosphere за терпеливые ответы на мои новичковые вопросы при подготовке публикации.
Комментарии (31)
M_AJ
22.04.2024 22:26взял USB-устройство попроще
Хоть бы сказали какое.
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.
dartraiden
22.04.2024 22:26+1Устройств попроще на алике полно по запросу "FIDO2"
До ответа автора я по фото даже подумал, что это что-то от KEY-ID, по внешнему виду очень похожи.
Raegdan
22.04.2024 22:26+1А ведь полностью аппаратный TOTP-токен тоже возможен. Пластина в формате банковской карты, только потолще. На борту eInk дисплей, всесистемный приемник GNSS для периодической коррекции локальных часов, и клавиатура с HEX набором. Буквы хекса вводят символы при вводе ключа, в остальных состояниях являются функциональными кнопками. Цифры всегда вводят цифры - ввод пин-кода при разблокировке и навигация. Питать это все от пары биосных батареек. Для дополнительной паранойи можно хранить базу в оперативке, питать ее через обрывную обмотку в стенках корпуса, и конструктивно обеспечить замену батареек только по очереди, для непрерывности питания.
ThingCrimson Автор
22.04.2024 22:26Да, возможен! В описанном Вами формате точно существовали аппартные генераторы HOTP; а впрочем вот нашёл и Feitian c200 TOTP:
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 я в спеке этого брелка не увидел.
ThingCrimson Автор
22.04.2024 22:26Скажу честно, глубоко в спецификации я не смотрел; время там каким-то образом всё же поддерживается более-менее точным; а вот что касается меню — очень может быть, что оно вообще для Одного-Единственного Самого Секретного Сервиса.
В любом случае, устройства с CTAP1 / CTAP2 делают такие аппаратные HOTP / TOTP токены устаревшими. Чем запоминать на устройстве секреты от разных сервисов, чтобы потом использовать достаточно примитивную математику для получения хэша — лучше взять за основу современное ассиметричное шифрование на эллиптических кривых; секретный ключ выжжен в устройстве, публичный сообщается сервису при регистрации и запоминается им. И всё, при аутентификации сервис посылает челлендж, токен отвечает на него и подписывает ответ своим секретным ключом; сервис проверяет ответ и подпись — бинго!
inkelyad
22.04.2024 22:26секретный ключ выжжен в устройстве
Защитники приватности шуметь будут. Потому что так получается, что один ключ используется в разных сервисах. Потому его и генерируют для каждого сервиса отдельно.
С другой стороны, выжеч прямо на фабрике и зашить в устройство можно пару десятков тысяч штук. Это всего ~300 килобайт для 128 битного ключа.
И пускай устройство последовательно предлагает, когда генерацию просят.
Но тут шуметь будут уже параноики-криптографы. Дескать, нет никакой гарантии, что фабрика эти ключики куда-нибудь не сохранила.
Raegdan
22.04.2024 22:26Ну это по сути обыкновенный USB-токен получается, с помощью которого бухгалтера логинятся в свои сбисы и диадоки. Тут загвоздка в том, что требуется двусторонний обмен между токеном и устройством, соответственно страдает или удобство, или универсальность, или дешевизна. А в чем несекурность TOTP, особенно если вовремя переходить на более современные криптопримитивы - не понимаю.
inkelyad
22.04.2024 22:26Ну это по сути обыкновенный USB-токен получается, с помощью которого бухгалтера логинятся в свои сбисы и диадоки.
Ну да. Я и написал, что не понимаю, почему не захотели воспользоваться всеми этими протоколами, а изобрели новый.
С точки зрения использования - что так, что так втыкаешь какое-то устройство в USB (ну или то же самое по Bluetooth/NFC)
Тут загвоздка в том, что требуется двусторонний обмен между токеном и устройством,
В момент создания учетки - он всегда требуется чтобы seed в токен попал. Сканирование QR-это именно оно. Ну, если он не зашивается на заводе. Но если зашивается - то ключ/публичная часть ключа должна как-то в сервис попасть. Они достаточно длинные, чтобы руками было не набрать, даже если токен его покажет.
А в чем несекурность TOTP, особенно если вовремя переходить на более современные криптопримитивы - не понимаю.
Нет защиты от MitM при регистрации, например. Или что seed хранится и у тебя и на стороне сервера и может оттуда утечь.
В более совершенных проколах над этим поработали. Особенно хорошо будет, если токен нормальным экраном обладает. Можно будет показать 'сайт example.com' хочет сгенерировать учетку, разрешить?
А в TOTP возможен сценарий, когда в основном сервисе регистрируется промежуточный товарищ, а тебе, для инициализации генератора - предлагает свой seed.
inkelyad
22.04.2024 22:26+2Однако сейчас нужно хотеть уже не генератор OTP (ну устаревает оно), а устройство для работы с Passkeys/WebAuthn, интерфейсами PC/SC и прочими CCID-образными.
Мне, кстати, интересно, почему на предыдущее поколение интерфейса ко всем этим токенам авторизации решили забить, а изобрели заново.
...И почему смартфоны, у которых USB, Bluetooth, NFC есть, аутентификатором по этим CCID образным интерфейсам работать не умеют.
А у устройства, показывающего циферки есть, кажется, только одно преимущество - явный air gap и, соответственно, никакого специализированного интерфейса от того устройства, где оно применяется, не требуется.
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/
inkelyad
22.04.2024 22:26Это не тот сценарий. Точнее, не тот интерфейс. Это, судя по англоязычному описанию того же - новые Passkeys.
Тот - это когда приложение хочет авторизации по железному токену вроде того самого, как у бухгалтера. А ты вместо токена - смартфон цепляешь и дальше работаешь с ним почти так же, как с тем токеном работал бы.
А Passkeys с соседнего устройства, насколько я понимаю - хочет наличия на том самом устройстве Интернет соединения. В отличии от аппаратных токенов.
xSVPx
22.04.2024 22:26Он не "возможен" - это единственный разумный вариант. И подобные устройства раньше давали нормальные банки. Только они там не тотр использовали, а вообще одноразовый шифр-блокнот.
Для тотр очевидно нужно устройство с вводом пина и выбором ключа. Ведь для разных сервисов хорошо бы разные ключи. И вот тут надо бы поискать. У меня руки не дошли пока :(
Ввод пароля по нажатию клавиши это в целом неплохо(а поддерживает ли он много ключей?), но яб лучше с экрана набил, удобнее как по мне. С телефоном к примеру неудобно по usb втыкать итп.
Raegdan
22.04.2024 22:26Я выше расписал, как вижу примерную логику девайса https://habr.com/ru/articles/809569/#comment_26754969
ThingCrimson Автор
22.04.2024 22:26Позволю себе не согласиться! Чуть выше я написал, что HOTP / TOTP (как и простыни с OTP, пользовался такими в одном банке лет 15 назад) это уже вчерашний день. А современное состояние дел — использование ассиметричного шифрования, когда один токен с намертво прошитым секретным ключом ползволяет использовать множество сервисов (которые на стадии инициализации 2FA зипоминают у себя публичный ключ токена).
xSVPx
22.04.2024 22:26Ну т.е. перехватив один "ответ", скажем в хабр ты логинился, можно будет украсть все твои деньги из банков, с биржи итп :)?
Прелестно.
Wesha
В имеющихся 2FA жутко бесит, что время должно быть достаточно точно синхронизировано между девайсами — а если второе устройство не имеет контактов с внешним миром, то время имеет тенденцию убегать, и в результате сгенерированный код не подходит. Другая проблема — часовые пояса: поскольку я нахожусь не в Москве, постоянно приходится на девайсе выставлять московское время, чтобы код для Сбера оказался правильный. Есть же для таких ситуаций UTC, которое по всему шарику одно и то же — но индейская народная национальная изба получается...
mmMike
Поскольку не раз реализовывал и использовал TOTP в разных проектах, то описанная ситуация несколько удивляет.
У TOTP есть параметр "период" и его редко ставят меньше 30 сек. Устройство в котором время убегает от сервера на хотя бы 5 сек (что бы это вызвало проблемы) за какой то разумный срок (месяц..два) без синхронизации - это странно.
То же очень странно. В стандартной реализации, на хосте у меня используется Math.floorDiv(System.currentTimeMillis()/1000L, period) и никаких проблем нет с UTC временем ни с одним сторонним токеном TOTP.
Потому что, по стандарту rfc6238 используется время UTC и никаких часовых поясов нет в принципе.
Wesha
У меня на "телефоне" (аппарат, у которого нет симки, то есть это просто "мобильный WiFi-терминал" время регулярно убегает на 2-3 минуты (Без симки синхронизировать время с сотовой сетью он почему-то не умеет), а установка "текущего времени" осуществляется как "укажи на циферблате, куда стрелки показывают" (а не "набери цифирки на клавиатуре"), в результате чего правильный TOTP-код получается попыткий так с пятой.
Очевидно, у сберовских программистов своеобразные понятия о том, что такое "стандартная реализация" (ни разу не удивлён, кстати, велосипед из костылей — наше всё). При установке правильной таймзоны и правильного текущего местного времени — индейская изба; при установке таймозны "Москва" и текущего московского времени — работает.
ThingCrimson Автор
Кстати, если у Вас часы на устройстве отстают — попробуйте
oathtool -w 10
скажем. Это сгенериует TOTP для текущего момента времени плюс 10 последующих периодов (30 секунд рекомендовано). Можно изловчиться в уме коррекцию делать: «ага, отстаём на две минуты, значит беру пятое выданное значение TOTP».А вот если спешат, тогда хуже… Ну и привязка к конкретной таймзоне остаётся — если бы в РФ была одна таймзона на всю страну, можно было бы сказать «так и задумано, чтоб только свои могли пользоваться», а так даже и не знаю.
CaptainFlint
Ничто не мешает точно так же сгенерировать код на любой момент времени, в том же oathtool можно задать произвольное время, а не только несколько будущих кодов. При желании можно даже скрипт наклепать, который запросит текущее время с какого-нибудь интернет-ресурса, сделает коррекцию на таймзону и вставит это значение в параметры oathtool'у вместо текущего. Другой вопрос, что запускать консольные программы на смартфоне — удовольствие ниже среднего, не говоря уж о том, что секретный код для генерации придётся тогда хранить не в конкретном приложении, а в общедоступной части файловой системы.
ThingCrimson Автор
Да, Вы правы, можно делать нечто вроде такого
oathtool -N $(date -ud "2 minutes 25 seconds ago")
Что касается консольных программ на смартфоне (хотя я именно от смартфона и старался уйти), то при наличии там полноценного линукса (iSH для iPhone, наверняка для Android есть аналог) — можно поставить туда кроме oathtool ещё и GPG, ну и
mytotp.sh
тогда тоже.(в сторону: делегация TLD .sh это прямо диверсия! пришлось упоминание своего скрипта как код оформлять, иначе считало это активной ссылкой)
CaptainFlint
Просто про смартфон автор ветки начал разговор, поэтому я и упомянул, что там будет не так удобно пользоваться консольной тулзой.
А вообще я лично тоже терпеть не могу пользоваться смартфоном как MFA-устройством. Крайне раздражающая и неудобная концепция.
dartraiden
Безопасность vs удобство, извечная дилемма.
mm3
Можно попробовать настроить на этом "телефоне" синхронизацию времени по GPS, была вроде такая фича некоторое время на андроиде, а если уже недоступна, то наверняка есть программы реализующие такой функционал.
inkelyad
Это не у них может быть. А у таблицы таймзон в какой-нибудь Java внутри телефона, которую забыли обновить. Потому что, скажем, некоторые варианты до сих пор думают, что в самарской таймзоне (если она вообще есть) времени есть переход на летнее время да еще и смещение не то, которое было. В результате в unixtime то самое текущее время, вводимое руками, неправильно пересчитывается.
Проверяется легко - ставим таймзону, синхронизируем время по NTP (не ставим руками и не берем с сотовой сети - там оно правильное смещение умеет передавать) через WiFi и смотрим, а правильно ли часы телефона время показывают.
Или по другому - поставить UTC зону, ввести UTC время, потом переставить зону, не трогая само время. И посмотреть показание часов/правильность кодов OTP.
ThingCrimson Автор
Кстати да, если время на устройстве выставляется местное, то возможны варианты с пересчётом в UTC при устаревшем tzdata — это Вы очень верно подметили!
ThingCrimson Автор
Воистину удивительные вещи могут сотворить одарённые люди при реализации хорошо документированных стандартов! Ведь в RFC 6238 явно прописано использовать UNIX time (Определяется как количество секунд, прошедших с полуночи (00:00:00 UTC) 1 января 1970 года (четверг)); да и целый раздел посвящён проблеме синхронизации, с рекомендацией:
Wesha
Хе, кожаные мешки уже который десяток лет костыляют "валидацию емейл-адреса" каждый в меру своего понимания (при том, что в RFC совсем другое написано), а Вы всё ещё на что-то надеетесь...
ThingCrimson Автор
Да, есть такое! Почитал Ваш перевод, полезная штука — и то, в RFC 3696 уже не упоминается UUCP bang notation (RFC 976) типа system!user@domain. Хорошо, если есть проверенные библиотеки (привет, supply chain attack!); а если делать самому ab ovo — то читать всю доступную документацию, включая лютое legacy.
А надеюсь я так, pro forma… Но всегда приятно быть удивлённым!