Додати в 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
  • Втрати чи викрадення файлу резервної копії (експорт під паролем)

Не захищає від

  • Зловмисного коду, що працює від імені користувача, поки сховище розблоковане
  • Кейлогера, який перехоплює пароль під час введення
  • Скомпрометованого браузера чи операційної системи
  • Зламу самих сервісів, для яких призначені коди

Коротко: це захищає дані у стані спокою. Пристрій, який під час роботи вже перебуває під контролем зловмисника, так захистити не можна — і ми цього не обіцяємо.

Дозволи

Маніфест оголошує рівно два дозволи й жодного host-дозволу:

storage
Облікові записи й налаштування в локальному сховищі, розблокований ключ у session storage і необов'язкова копія для синхронізації
activeTab
Читає ім'я хоста активної вкладки, щоб підсвітити відповідний обліковий запис, і робить знімок вкладки, коли користувач сканує QR-код з екрана

У розширенні немає content-скриптів, немає дозволів tabs, cookies і webRequest та немає web-accessible-ресурсів. Розширення не може читати чи змінювати вміст жодної сторінки.

Камера

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

Мережеві запити

За звичайної роботи розширення не робить жодних автоматичних запитів, а Manifest V3 забороняє віддалений код. Усі з'єднання, які взагалі можливі:

ХостКолиПередає дані користувача?
worldtimeapi.org
timeapi.io
Перевірка розходження годинника, кешується, у разі помилки мовчки пропускається. Зі збитим годинником TOTP ламається.Ні
authenticator.shСторінка привітання під час встановлення; сторінка зворотного зв'язку під час видалення або оцінювання.Ні (звичайні логи вебсервера)

Ні шрифти, ні скрипти, ні стилі, ні зображення не завантажуються зі сторонніх хостів. Усе потрібне для відображення інтерфейсу лежить усередині пакета.

Як перевірити те, що ми публікуємо

Нічого з переліченого не треба брати на віру. Розширення має відкритий код, і кожен реліз відтворюваний:

  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 — на сторінці політики безпеки; що зберігається і що залишає пристрій — у політиці конфіденційності.

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

З усього, що не стосується безпеки — встановлення, відновлення доступу, питання оплати під час розгортання — див. підтримку. Будь ласка, не надсилайте туди повідомлень про вразливості: ця скринька не вважається конфіденційною.