Сьогодні ми на Product Hunt! Залишити коментар
Вийшла версія Authenticator 1.16.0. Що нового
Технічний огляд для тих, хто перевіряє безпеку. Усе викладене можна звірити з вихідним кодом — зокрема й те, що нас не прикрашає: ми це називаємо, а не оминаємо.
Це розширення Chrome на Manifest V3, яке генерує коди TOTP локально за допомогою OTPAuth. Генерування кодів, зберігання облікових записів і їх шифрування обходяться без бекенду, а реєстрації користувачів у нас немає. Ми тримаємо один сервер, api.authenticator.sh, для безкоштовного тарифу й Pro — його описано нижче, — і він ніколи не отримує ні секретів, ні назв облікових записів, ні видавців, ні кодів.
Цей сервер не зберігає ключового матеріалу для чиїхось облікових записів: немає ні депонування ключів, ні будь-якого шляху відновлення, який контролювали б ми. Якщо користувач забув пароль і втратив код відновлення, ми не зможемо зарадити — так задумано.
Захист паролем необов'язковий і типово вимкнений. Коли його ввімкнено:
Дані ніколи не шифруються ключем, виведеним із пароля, безпосередньо. Записи шифрує випадковий майстер-ключ; вивід PBKDF2 лише огортає цей майстер-ключ. Звідси два наслідки, і обидва важливі:
Коли захист паролем увімкнено, шифрується весь запис облікового запису, крім ідентифікатора та відбитка — зокрема й назва сервісу, тож із викраденого профілю не зрозуміти, обліковими записами яких сервісів володіє користувач. Під час увімкнення розширення шифрує записи, перевіряє їх розшифруванням і порівнянням і лише тоді видаляє всі копії у відкритому вигляді: з локального сховища браузера, із синхронізації та з усіх семи ротованих знімків резервних копій.
Кажемо прямо, бо для вашої оцінки це суттєво:
Коротко: це захищає дані у стані спокою. Пристрій, який під час роботи вже перебуває під контролем зловмисника, так захистити не можна — і ми цього не обіцяємо.
Маніфест оголошує п'ять дозволів і жодного дозволу на хости:
Немає немає content-скриптів, немає дозволів tabs, cookies чи webRequest і немає web-accessible resources. Нічого нашого не існує на сторінці, доки ви не попросите там код; те, що тоді виконується, впроваджується для тієї однієї вкладки й того одного виклику, за дозволом, який дає ваш власний клік, і не лишає по собі нічого.
Сканування QR-коду камерою працює на сторінці розширення, відкритій у вкладці, а не у спливному вікні: popup знищується, щойно втрачає фокус, а запит дозволу саме це й робить. Для цього не потрібен дозвіл у маніфесті: використовується штатний запит камери браузера, який видається на origin розширення та відкликається в налаштуваннях сайту, і він ніколи не з'являється, доки користувач не відкриє сканер. Відео декодується локально, нікуди не передається й не зберігається.
Починаючи з 1.14.0 розширення раз на добу звертається до api.authenticator.sh — під час запуску браузера або після того, як відмалювалося вікно розширення, і ніколи на шляху до показу коду. Запит — це закритий перелік полів: його формує одна функція в src/billing/sync.ts, а тест не дає цьому переліку розширитися:
Ніколи не надсилаються: секрети, назви облікових записів, видавці, коди чи сайти, на яких їх використовують. Країну сервер визначає із запиту на своєму edge-вузлі й IP-адресу не зберігає. Сторінка видалення отримує той самий ідентифікатор установки як ?i=: вона повідомляє серверу, що установку видалено, і пов'язує з нею необов'язкову відповідь в опитуванні.
Для цього в chrome.storage.local зберігаються ідентифікатор установки, остання підписана політика й ліцензія, ліцензійний ключ цієї установки (введений вручну або отриманий після покупки в ній), лічильники відкриттів за днями, доки їх не отримає сервер, і події в черзі — жодних даних облікових записів. Поки ввімкнено синхронізацію, ознака того, що установка старша за білінг, і цей ліцензійний ключ потрапляють також у Chrome Sync, щоб їх підхопили інші профілі Chrome цього користувача й самі ввімкнули Pro; якщо вимкнути синхронізацію, обидва видаляються з Chrome Sync, а після повторного ввімкнення повертаються.
Що повертається і як розширення з цим поводиться:
Ліміт — це не DRM: код відкритий, і форк може його прибрати. Що ніколи не має бути можливим — це отримати чи використати чужу ліцензію або зробити обмеженою чужу установку: таке є вразливістю й підпадає під дію нашої політики безпеки.
Самостійно розширення робить два види запитів: перевірку годинника та щоденну звірку з сервером для білінгу. Усе інше нижче стається тому, що користувач на це натиснув. Manifest V3 забороняє віддалений код, і ніщо з переліченого не передає ні облікових записів, ні секретних ключів, ні згенерованих кодів. Повний перелік:
| Хост | Коли | Передає дані користувача? |
|---|---|---|
| time.akamai.com timeapi.io cloudflare.com | Перевірка розходження годинника, кешується; якщо жодне джерело недоступне, про це сказано в налаштуваннях. Зі збитим годинником TOTP ламається. | Ні |
| authenticator.sh | Сторінка привітання під час встановлення; сторінка зворотного зв'язку під час видалення, з ідентифікатором установки в адресі; сторінки довідки та підтримки, коли їх відкривають із вікна розширення. | Ідентифікатор установки — лише на сторінці видалення; в інших випадках ні (звичайні логи вебсервера) |
| api.authenticator.sh | Звірка для білінгу раз на добу; запити оплати, ліцензії та порталу, коли користувач купує Pro, вводить ключ, відновлює покупку або керує підпискою. | Поля, перелічені вище, — ніколи не дані облікових записів. Ліцензійний ключ чи адресу email — лише коли користувач сам їх вводить |
| checkout.stripe.com billing.stripe.com | Stripe Checkout і клієнтський портал, відкриваються у вкладці, коли користувач купує Pro або керує підпискою. | Те, що покупець там вводить. Діють власні умови Stripe і Link |
| chromewebstore.google.com | Сторінка в магазині, відкривається у вкладці лише за кліком: форма відгуку — з пропозиції оцінити. | Ні (для Google це звичайний захід на сторінку магазину) |
Ні шрифти, ні скрипти, ні стилі, ні зображення не завантажуються зі сторонніх хостів. Усе потрібне для відображення інтерфейсу лежить усередині пакета.
Нічого з переліченого не треба брати на віру. Розширення має відкритий код, і кожен реліз відтворюваний:
.crx з Chrome Web Store і розпакуйте йогоnpm ci && npm run build на Node 20 LTSdist/ з розпакованим пакетомSHA-256 для кожного файлу в зібраному dist/ публікується з кожним релізом на GitHub у вигляді SHA256SUMS-v<version>.txt, у форматі sha256sum — тож крок 4 зводиться до одного запуску sha256sum -c. Розбіжності мають обмежуватися порядком файлів усередині архівів і пробілами в мініфікованому виводі на різних патч-версіях Node.
Залежностей у рантаймі свідомо мало — OTPAuth, React, jsQR, Zustand, Framer Motion і Lucide — усі зафіксовані закомміченим lock-файлом. SBOM у форматі CycloneDX надаємо на запит.
Переглянути вихідний кодМи невеликий незалежний розробник. Якщо щось із переліченого для вашого процесу обов'язкове, краще дізнатися про це зараз, а не на третьому тижні оцінювання:
Натомість ми пропонуємо повну прозорість вихідного коду, перевірювану збірку, мінімальний набір дозволів і сервер, якому ваші секрети, назви облікових записів чи коди взагалі ніколи не надсилаються.
Повідомлення про вразливості та питання щодо безпеки: security@authenticator.sh. Політика розкриття, межі застосування, строки відповіді й умови safe harbour — на сторінці політики безпеки; що зберігається і що залишає пристрій — у політиці конфіденційності.
Ми готові заповнити письмову анкету оцінювання постачальника або розібрати код разом із вашою командою безпеки.
З усього, що не стосується безпеки — встановлення, відновлення доступу, питання оплати під час розгортання — див. підтримку. Будь ласка, не надсилайте туди повідомлень про вразливості: ця скринька не вважається конфіденційною.