Отладчик кодов TOTP / 2FA

Генерация и отладка кодов TOTP / 2FA: полный вывод по RFC 6238, проверка с окном дрейфа и разбор otpauth:// — всё в вашем браузере.

Время

Введите секрет, чтобы увидеть код.

otpauth:// URI для этой конфигурации
otpauth://totp/user%40example.com?secret=JBSWY3DPEHPK3PXP&algorithm=SHA1&digits=6&period=30

Что на самом деле такое эти шесть цифр

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

TOTP (RFC 6238) — тонкая надстройка над более старой схемой HOTP (RFC 4226). HOTP превращает секрет и счётчик в код; TOTP — это просто HOTP со счётчиком, равным числу временных шагов от начала эпохи Unix. В этом вся идея: разделите текущее время Unix на длину шага (по умолчанию 30 секунд) и подайте результат в HOTP. Этот инструмент показывает каждый шаг того расчёта, потому что когда код не проходит проверку, ответ почти всегда виден где-то в выводе.

Вывод, шаг за шагом

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

  • Счётчик. Возьмите время Unix в секундах, вычтите T0 (0 в любом реальном развёртывании), разделите на период и округлите вниз. При шагах в 30 секунд любой момент в те же полминуты даёт тот же счётчик, поэтому код действует столько, сколько действует.
  • HMAC. Запишите счётчик как 8 байт в порядке big-endian и вычислите HMAC(секрет, счётчик) с выбранным хешем — SHA-1 почти во всех приложениях. Это даёт 20-байтовый дайджест для SHA-1 (32 для SHA-256, 64 для SHA-512).
  • Смещение. Возьмите четыре младших бита последнего байта дайджеста. Это число от 0 до 15, и оно указывает, откуда читать в дайджесте — динамическое усечение, чтобы один и тот же секрет не всегда использовал одни и те же байты.
  • 31-битное значение. Прочитайте четыре байта начиная со смещения и замаскируйте старший бит (чтобы избежать путаницы со знаком). Остаётся 31-битное целое.
  • Код. Возьмите это целое по модулю 10^цифр и дополните нулями слева. Шесть цифр — почти универсальный выбор; семь и восемь существуют и допустимы.

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

Почему код не совпадает — три обычные причины

Несовпадение TOTP никогда не приходит с сообщением об ошибке; код просто неверен. На практике это почти всегда одно из трёх, и панели здесь расставлены так, чтобы их различить:

  • Секрет прочитан в неверном формате. Секрет аутентификатора — это Base32, но те же символы, прочитанные как hex — или секрет, который на самом деле был hex, прочитанный как Base32 — дают совершенно другие байты и совершенно другой код. Переключите формат и посмотрите, какой даёт ожидаемый код.
  • Отличается параметр. Подавляющее умолчание — HMAC-SHA-1, 6 цифр, период 30 секунд. Сервер с SHA-256, или 8 цифрами, или шагом в 60 секунд разойдётся с приложением, оставленным на значениях по умолчанию. otpauth:// URI несёт все три, поэтому сканирование QR попадает в них верно, а ручной ввод секрета зачастую нет.
  • Часы разошлись. TOTP предполагает, что обе стороны согласны о времени. Если часы телефона спешат на минуту, его код на минуту впереди серверного. Для этого и нужно окно дрейфа: проверка кода по шагам с обеих сторон от «сейчас» говорит не только о совпадении, но и о том, насколько сдвинуты часы.

RFC 6238 рекомендует окно проверки не более одного шага с каждой стороны — достаточно, чтобы поглотить обычный сдвиг часов и гонку в момент смены, не расширяя пространство перебора больше необходимого. Этот инструмент по умолчанию использует ±1 и позволяет расширить его при отладке.

Секреты, Base32 и otpauth:// URI

Секрет передаётся один раз, при настройке, и всё остальное выводится из него. Приложения-аутентификаторы кодируют его в Base32 (RFC 4648) — алфавит A–Z и 2–7, который избегает легко путаемых символов и переживает печать под QR. Этот инструмент по умолчанию читает Base32, игнорируя пробелы, которые приложения добавляют для читаемости, и регистр, а также принимает hex, чтобы вы могли воспроизвести тестовые векторы RFC 6238, секреты которых заданы как сырые байты.

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

otpauth://totp/GitHub:[email protected]?secret=JBSWY3DPEHPK3PXP&issuer=GitHub&algorithm=SHA1&digits=6&period=30

Принимается только тип totp. otpauth://hotp URI несёт счётчик вместо периода, и трактовка его как TOTP молча дала бы неверные коды — поэтому он отклоняется, а не угадывается.

Алгоритм, цифры и период

RFC 6238 допускает HMAC-SHA-1, SHA-256 или SHA-512, от шести до восьми цифр и любую длину шага. На практике мир остановился на SHA-1, шести цифрах и тридцати секундах, и большинство приложений реализуют только это сочетание — сервер, выбравший иное, вынужден надеяться, что приложение пользователя последует, а многие нет. Безопасный выбор для совместимости — скучный.

Стоит прямо разобрать вопрос про SHA-1, ведь инструмент хеширования на этом сайте помечает SHA-1 как сломанный. Оба утверждения верны. SHA-1 непригоден для цифровых подписей, потому что атакующие могут изготовить коллизии — два документа с одинаковым хешем. TOTP не зависит от этого свойства: его безопасность идёт от секретного ключа внутри HMAC, а не от стойкости хеша к коллизиям, и HMAC-SHA-1 остаётся надёжным. Использовать здесь SHA-256 допустимо, но даёт мало и стоит совместимости с приложениями, умеющими только SHA-1.

Что этот инструмент защищает, а что нет

Всё здесь выполняется в вашем браузере. HMAC вычисляется через Web Crypto API на вашем устройстве — тот же примитив, что используют инструменты хеширования и HMAC — и ничто из введённого — секрет, код или otpauth URI — не загружается, не хранится и не записывается. Это свойство того, что код работает на стороне клиента, а не обещание, которое надо принять на веру.

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

Частые вопросы

Отправляется ли мой секрет на сервер?
Нет. Код вычисляется в вашем браузере через Web Crypto API, и ничто из введённого не загружается и не записывается. Поскольку секрет TOTP — это второй фактор, всё же будьте осторожны при вставке рабочего секрета — он может пройти через буфер обмена и историю браузера, как любой текст.
Почему мой код не совпадает с моим аутентификатором?
Почти всегда одно из трёх: секрет прочитан в неверном формате (Base32 против hex), параметр отличается от умолчаний (большинство приложений — SHA-1, 6 цифр, период 30 секунд), или часы устройства разошлись. Панель вывода изолирует первые два, а проверка с окном дрейфа ± выявляет третье.
В чём разница между TOTP и HOTP?
HOTP (RFC 4226) вычисляет код из секрета и счётчика, растущего при каждом использовании. TOTP (RFC 6238) — та же конструкция со счётчиком, равным числу временных шагов от эпохи Unix, так что код меняется с часами, а не с нажатием. TOTP — это то, что используют приложения-аутентификаторы.
Почему SHA-1 — умолчание, если в других местах он сломан?
SHA-1 сломан для подписей, потому что можно построить коллизии, но HMAC — на котором построен TOTP — не зависит от стойкости к коллизиям; его безопасность держится на секретном ключе. HMAC-SHA-1 надёжен и является единственным алгоритмом, который реализуют многие аутентификаторы, поэтому это и безопасное, и совместимое умолчание.
Можно ли закрепить код за конкретным временем?
Да. Переключите время с «вживую» на «зафиксировано» и введите метку времени Unix. Код тогда остаётся статичным — так воспроизводят опубликованный тестовый вектор (RFC 6238 даёт значения на временах вроде 59 и 1111111109) или проверяют, какой код был действителен в прошлый момент.
Каким должно быть окно дрейфа?
RFC 6238 рекомендует не более одного шага с каждой стороны — это и есть умолчание инструмента. Более широкое окно терпит сильнее разошедшиеся часы, но и расширяет множество кодов, которые сервер принял бы, так что это компромисс; ±1 — стандартный баланс.
Зачем нужны цифры и период?
Цифры — это сколько разрядов в коде: шесть почти везде, семь или восемь там, где сервис хочет чуть больше стойкости. Период — сколько секунд код остаётся действительным, по умолчанию тридцать. Оба входят в otpauth:// URI, и оба должны совпадать на двух сторонах, иначе коды не сойдутся.