Перейти к содержимому

Двухфакторная защита

Одноразовые коды внутри профиля

У профиля может лежать ключ двухфакторной защиты того аккаунта, в который он заходит. Программа сама превращает ключ в текущий код, в том же окне и без телефона.
RFC 6238 поверх RFC 4226
Стандарт
6 знаков, шаг 30 секунд
Код
SHA1, SHA256, SHA512
Алгоритмы
На вашей машине, без сети
Где считается

Телефон не тянет полсотни

Двухфакторная защита перестала быть необязательной. Площадки, рекламные кабинеты и социальные сети просят шесть знаков при каждом входе.

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

Что меняется с ключом внутри профиля

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

  • Второе устройство не нужно

    Код появляется в том же окне, где живёт профиль.

  • Не надо искать нужную запись

    Ключ принадлежит профилю, сопоставлять по названию нечего.

  • Не надо спешно перепечатывать

    Код вы копируете кнопкой, а в форму его впишет сценарий.

  • В сеть ничего не уходит

    Программа делает код из ключа прямо на этом компьютере.

Куда ложится ключ

Откройте меню на карточке профиля и выберите «Одноразовый код». Если ключа ещё нет, окно попросит его вместо того, чтобы показывать цифры.

Вставить можно любой вид: голый ключ, который сайт печатает рядом с картинкой QR, или целую строку otpauth://, зашитую в саму картинку. Из строки программа читает издателя, имя аккаунта, число знаков, шаг и алгоритм, поэтому необычный сайт лучше вставлять строкой.

Четыре шага до первого кода

  1. 1

    Откройте меню профиля

    «Одноразовый код» стоит в том же меню, что «Отпечаток» и «Данные для входа».

  2. 2

    Вставьте ключ

    JBSWY3DPEHPK3PXP или otpauth://totp/... Пробелы, дефисы, нижний регистр и знаки = не мешают.

  3. 3

    Сохраните

    Негодный ключ программа вернёт ошибкой, и на диск ничего не ляжет.

  4. 4

    Посмотрите на карточку

    На профиле появляется отметка 2FA: сразу видно, каким аккаунтам телефон уже не нужен.

Как получается код

Расчёт идёт по RFC 6238 поверх RFC 4226, по тому же стандарту, что и приложение в телефоне. Текущее время делится на шаг, полученный счётчик идёт через HMAC с вашим ключом, и оттуда режутся те самые знаки, которые просит форма входа.

Счётчик уходит в восемь байтов двумя половинами, как и требует стандарт, поэтому короткая четырёхбайтовая запись нас не подведёт. Сходятся все шесть эталонов, дальний из них на t=20000000000.

Ничего никуда не уходит: ключ остаётся у вас в файле, а считает код сама программа, поэтому он появится и при полностью отключённой сети.

НастройкаПо умолчаниюЧто принимается
Число знаков66, 7 или 8, если так сказано в строке otpauth
Шаг30 секундот 1 до 300 секунд из той же строки
АлгоритмHMAC-SHA1SHA1, SHA256 и SHA512
Вид ключаbase32пробелы, дефисы, нижний регистр и знаки =

Что видно в окне

Код стоит крупно посередине и разбит по три знака: «482 913» глазами переносится в форму легче, чем «482913». Кнопка копирования кладёт его в буфер обмена уже без пробела.

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

Строка выше называет издателя и имя аккаунта, прочитанные из строки. Именно она подтверждает, что код относится к нужному аккаунту, когда профиль один из пятидесяти.

Скрипт спрашивает код

В программе есть локальный API по HTTP для программ на этом же компьютере. Он выключен, пока вы его не включите, слушает только петлевой адрес, и токен несёт каждый вызов, кроме одного: состояние интерфейса спрашивается без него.

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

ИИ-помощник ходит по тому же адресу через встроенный сервер MCP, под тем же токеном и с теми же отказами.

Вызов
GET /api/v1/profile/code?profileId=p-42
Токен
параметр token, заголовок x-api-token или Authorization: Bearer
Ответ
{ "code": 0, "data": { "code": "482913", "secondsRemaining": 17, "issuer": "Shop" } }
У профиля нет ключа
code -1, msg no_2fa_key
Токена нет или он не тот
HTTP 401
Запрос пришёл со страницы
Отказ, каким бы ни был токен

Ноль это состояние ответа, общее для всех вызовов. Сами шесть знаков лежат в data.code.

Экран «Локальный API автоматизации» в ARMANOS: переключатель «Включить локальный API» включён и помечен «Запущен», адрес http://127.0.0.1:50325 и токен доступа с кнопкой копирования.
Интерфейс выключен, пока вы его не включите. Токен с этого экрана скрипт шлёт при каждом вызове, включая запрос кода; без токена отвечает только вопрос, включён ли интерфейс.

Сценарий вписывает код сам

На экране «Сценарии» любое текстовое поле шага принимает {{profile.totp}}. Поставьте это в шаг ввода, нацеленный на поле кода, и сценарий заполнит его наравне с остальной формой.

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

В журнал шагов код не попадает: вместо значения из переменной там стоят четыре точки. Сценарий щёлкает в поле, стирает старое сочетанием клавиш и вводит код целиком, одним настоящим вводом. Если форма ждёт нажатий по буквам, поставьте код в шаг «Набрать как человек».

Ключ остаётся на компьютере

Ключ лежит в profiles.json в папке данных программы, рядом с остальными настройками профиля. Обрыв питания не порвёт его пополам: на месте останется либо целый старый файл, либо целый новый.

У файла стоят права «только хозяин», и они уезжают вместе с ним в резервную копию или в облачную папку. На Windows они не значат ничего, и файл там бережёт сама папка пользователя, куда другие учётные записи без прав администратора не заходят.

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

На диске ключ не зашифрован

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

Полсотни ключей из таблицы

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

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

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

Чего это не делает

  • Это не хранилище паролей. Один ключ на профиль, без общего сейфа, без поиска по ключам и без места для запасных кодов, которые выдаёт сайт.
  • На диске ключ лежит незашифрованным. На macOS и Linux его закрывают права на файл, на Windows только папка пользователя.
  • Потерянный ключ потерян. На сервер он не уходит, и восстановить его по выданным кодам программа не может.
  • Картинок программа не читает. Вы вставляете текст ключа или строку otpauth://, а снимок QR или экран телефона она не разбирает.
  • Код идёт по часам этого компьютера. Если часы уехали, сайт код не примет, и программа об этой причине не предупредит.

Как проверить

За каждым утверждением выше стоит файл, а у большинства ещё и стенд, который падает, когда утверждение перестаёт быть правдой.

Коды сходятся со всеми шестью эталонными векторами RFC 6238, включая самый дальний
apps/desktop/src/lib/totp.js · apps/desktop/test/totp.js
Файл с ключом пишется правами «только хозяин», а оставшиеся открытыми файлы закрываются при запуске
apps/desktop/src/lib/secureFile.js · apps/desktop/test/secrets-on-disk.js
Код отдаётся только по токену и никогда веб-странице
apps/desktop/src/lib/local-api.js · apps/desktop/test/local-api-gate.js
Сценарий считает код в момент подстановки
apps/desktop/src/main/main.js · apps/web/test/страница-возможностей.js
Восстановленный профиль сохраняет число знаков, шаг и алгоритм
apps/desktop/src/main/main.js · apps/desktop/test/config-import-2fa.js

Вопросы

Это тот же второй шаг, что при входе в ARMANOS?
Нет. Этот ключ принадлежит аккаунту, в который заходит профиль, а второй шаг входа в вашу собственную учётную запись ARMANOS живёт на сервере и с запасными кодами.
А если сайт выдаёт 8 знаков или шаг в 60 секунд?
Вставьте целую строку otpauth://, она несёт эти настройки сама. У голого ключа их нет, поэтому программа берёт привычные значения, а строку, считающую входы вместо секунд, не принимает вовсе.
Может ли страница из сети прочитать мой код?
Нет. Вызов, похожий на пришедший со страницы, программа отклонит при любом токене: его выдают заголовок Origin, значение Sec-Fetch-Site, отличное от none, или чужой адрес узла.
Уезжает ли ключ на вторую машину?
Войдя на другой машине, вы ключа там не найдёте: на сервере такого поля попросту нет. Привезёт его только перенос профиля, под вашим паролем, а экспорт профилей вырезает секреты, пока вы не нажмёте «Включить секреты», и из отчёта о проблеме ключ вырезан всегда.
Что происходит при замене и удалении ключа?
«Заменить ключ» ставит новый: так делают после повторной привязки аккаунта. «Удалить» сначала спрашивает, а в журнале правок остаётся только сам факт замены, без значения.
Можно раздать ключи уже готовым профилям?
По одному, в окне профиля. Отдельного действия для всех сразу нет: полсотни ключей приезжают столбцом таблицы в тот момент, когда вы создаёте профили.

Пусть ключ лежит там, где живёт аккаунт

В ARMANOS добавьте ключ одному профилю и увидите код в том же окне.