Вышла версия Authenticator 1.13.0. Что нового

Установить в Chrome

Как это работает

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

Архитектура

Бэкенда нет. Это расширение Chrome на Manifest V3, которое генерирует коды TOTP/HOTP локально с помощью OTPAuth. Мы не держим серверов, не заводим учётных записей, и у нас нет канала, по которому данные пользователя могли бы к нам попасть.

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

Криптография

Защита паролем необязательна и по умолчанию выключена. Когда она включена:

Шифр
AES-256-GCM, случайный 96-битный IV для каждой записи и каждой перезаписи
Выработка ключа
PBKDF2-HMAC-SHA256, 600 000 итераций, случайная 128-битная соль (по рекомендациям OWASP)
Мастер-ключ
256 бит, из crypto.getRandomValues, генерируется один раз; пароль лишь оборачивает его
Отпечатки
HMAC-SHA256 на подключе, выведенном через HKDF; нужны для сведения записей между устройствами
Хранение разблокированного ключа
chrome.storage.session — только в памяти, никогда не пишется на диск, очищается при закрытии браузера, недоступен из content-скриптов
Автоблокировка
При каждом открытии / через 5, 15, 60 минут простоя / до закрытия браузера
Реализация
Только WebCrypto. Ни один примитив не написан вручную, никакая криптобиблиотека не поставляется в сборке.

Почему ключей два уровня

Данные никогда не шифруются ключом, выведенным из пароля, напрямую. Записи шифрует случайный мастер-ключ; вывод PBKDF2 только оборачивает этот мастер-ключ. Отсюда два следствия, и оба важны:

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

Что шифруется, а что нет

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

Говорим прямо, потому что для вашей оценки это существенно:

  • Если защита паролем выключена, аккаунты хранятся незашифрованными и, если включена синхронизация Chrome, реплицируются через собственный аккаунт Google пользователя. К нам они не попадают никогда, но Google их хранит. Синхронизацию можно отключить — это заодно удалит и то, что там уже есть.
  • История использования по сайтам — какой аккаунт применяется на каком домене — хранится локально и, пока собирается, хранилищем не защищена. Включение защиты паролем её удаляет; её также можно отключить отдельно.

Модель угроз

Защищает от

  • Кражи или копирования каталога профиля браузера
  • Вредоносных программ-стилеров, выгружающих данные браузера целиком
  • Физического доступа к оставленному без присмотра компьютеру
  • Попадания записей аккаунтов в Google через синхронизацию Chrome
  • Потери или кражи файла резервной копии (экспорт под паролем)

Не защищает от

  • Вредоносного кода, работающего от имени пользователя при разблокированном хранилище
  • Кейлоггера, перехватывающего пароль в момент ввода
  • Скомпрометированного браузера или операционной системы
  • Взлома самих сервисов, для которых предназначены коды
  • Незашифрованного экспорта, который вы сделали сами, — обычный JSON, ссылки otpauth:// или CXF прочитает любой, кто откроет файл

Коротко: это защищает данные в состоянии покоя. Устройство, которое уже находится под контролем атакующего во время работы, так защитить нельзя — и мы этого не обещаем.

Разрешения

Манифест объявляет пять разрешений и ни одного host-разрешения:

storage
Аккаунты и настройки в локальном хранилище, разблокированный ключ в session storage и необязательная копия для синхронизации
activeTab
Читает имя хоста активной вкладки, чтобы подсветить подходящий аккаунт, и делает снимок вкладки, когда пользователь сканирует QR-код с экрана
contextMenus
Добавляет пункт «Вставить код 2FA» в контекстное меню — и только на редактируемых полях страниц http(s)
scripting
Внедряет ту единственную функцию, которая кладёт код в поле, — для одной вкладки и одного вызова, только после выбора этого пункта меню
sidePanel
Открывает приложение в боковой панели Chrome, если выбран этот режим; доступа к страницам не даёт

В расширении нет content-скриптов, нет разрешений tabs, cookies и webRequest и нет web-accessible-ресурсов. Ничего нашего на странице не существует, пока вы не попросите там код; то, что выполняется потом, внедряется для одной этой вкладки и одного этого вызова, по разрешению, которое даёт ваш собственный клик, и не оставляет после себя ничего.

Камера

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

Сетевые запросы

Проверка часов — единственный запрос, который расширение делает самостоятельно; всё остальное ниже происходит потому, что пользователь на это нажал. Manifest V3 запрещает удалённый код, и ничто из перечисленного не передаёт ни аккаунты, ни секретные ключи, ни сгенерированные коды. Полный список:

ХостКогдаПередаёт данные пользователя?
time.akamai.com
timeapi.io
cloudflare.com
Проверка расхождения часов, кэшируется; если ни один источник недоступен, об этом сказано в настройках. При сбитых часах TOTP ломается.Нет
authenticator.shСтраница приветствия при установке; страница обратной связи при удалении; страницы помощи и поддержки, когда их открывают из окна расширения.Нет (обычные логи веб-сервера)
chromewebstore.google.comСтраница в магазине, открывается во вкладке только по клику: форма отзыва — из предложения оценить, наш менеджер паролей — из баннера кросс-промо.Нет (для Google это обычный заход на страницу магазина)
authenticator.featurebase.appПубличная доска пожеланий, открывается во вкладке по ссылке предложения новой функции в панели поддержки.Только то, что пользователь там опубликует. Сторонний сервис со своими условиями.

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

Как проверить то, что мы публикуем

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

  1. Скачайте опубликованный .crx из Chrome Web Store и распакуйте его
  2. Переключитесь на соответствующий git-тег
  3. Выполните npm ci && npm run build на Node 20 LTS
  4. Сравните получившийся dist/ с распакованным пакетом

SHA-256 для каждого файла в собранном dist/ публикуется с каждым релизом на GitHub в виде SHA256SUMS-v<version>.txt, в формате sha256sum — так что шаг 4 сводится к одному запуску sha256sum -c. Расхождения должны ограничиваться порядком файлов внутри архивов и пробелами в минифицированном выводе на разных патч-версиях Node.

Зависимостей в рантайме намеренно мало — OTPAuth, React, jsQR, Zustand, Framer Motion и Lucide — и все они зафиксированы закоммиченным lock-файлом. SBOM в формате CycloneDX предоставляем по запросу.

Смотреть исходный код

Чего у нас нет

Мы небольшой независимый разработчик. Если что-то из перечисленного для вашего процесса обязательно, лучше узнать об этом сейчас, а не на третьей неделе оценки:

  • Нет сертификации SOC 2, ISO 27001 или аналогичной
  • Независимый пентест до сих пор не заказывался
  • Нет платной программы bug bounty

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

Как с нами связаться

Сообщения об уязвимостях и вопросы по безопасности: security@authenticator.sh. Политика раскрытия, границы применимости, сроки ответа и условия safe harbour — на странице политики безопасности; что хранится и что покидает устройство — в политике конфиденциальности.

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

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