Dodaj do Chrome

Jak to działa

Przegląd techniczny dla osób audytujących bezpieczeństwo. Wszystko tutaj da się sprawdzić w kodzie źródłowym — łącznie z tym, co stawia nas w gorszym świetle i co nazywamy wprost, zamiast pomijać.

Architektura

Nie ma backendu. To rozszerzenie Chrome w Manifest V3, które generuje kody TOTP/HOTP lokalnie przy użyciu OTPAuth. Nie prowadzimy serwerów, nie zakładamy kont i nie mamy kanału, którym dane użytkownika mogłyby do nas trafić.

Skoro nie ma serwera, nie ma też materiału klucza po stronie serwera, depozytu kluczy ani żadnej ścieżki odzyskiwania kontrolowanej przez nas. Jeśli ktoś zapomni hasła i zgubi kod odzyskiwania, nie jesteśmy w stanie pomóc — tak to zaprojektowaliśmy.

Kryptografia

Ochrona hasłem jest opcjonalna i domyślnie wyłączona. Gdy jest włączona:

Szyfr
AES-256-GCM, losowy 96-bitowy IV dla każdego rekordu i każdego zapisu
Wyprowadzanie klucza
PBKDF2-HMAC-SHA256, 600 000 iteracji, losowa 128-bitowa sól (zgodnie z zaleceniami OWASP)
Klucz główny
256 bitów, z crypto.getRandomValues, generowany jednorazowo; hasło jedynie go opakowuje
Odciski
HMAC-SHA256 na podkluczu wyprowadzonym przez HKDF, służy do scalania rekordów między urządzeniami
Przechowywanie odblokowanego klucza
chrome.storage.session — wyłącznie w pamięci, nigdy nie zapisywany na dysk, czyszczony przy zamknięciu przeglądarki, nieosiągalny dla content scriptów
Automatyczna blokada
Przy każdym otwarciu / po 5, 15 lub 60 minutach bezczynności / do zamknięcia przeglądarki
Implementacja
Wyłącznie WebCrypto. Żaden prymityw nie jest pisany ręcznie i żadna biblioteka kryptograficzna nie trafia do paczki.

Dlaczego dwa poziomy klucza

Dane nigdy nie są szyfrowane bezpośrednio kluczem wyprowadzonym z hasła. Rekordy szyfruje losowy klucz główny; wynik PBKDF2 tylko opakowuje ten klucz główny. Wynikają z tego dwie rzeczy i obie mają znaczenie:

  • Zmiana hasła przepisuje 32 bajty zamiast ponownie szyfrować każdy rekord, każdą kopię zapasową i każdy eksport. To właśnie przy takich masowych zapisach systemy przechowywania gubią dane.
  • 160-bitowy kod odzyskiwania może niezależnie opakować ten sam klucz główny, więc zapomniane hasło nie oznacza utraty danych. Kod pokazywany jest raz, trzeba go przepisać dla potwierdzenia i jest wymieniany po każdym użyciu. Nic nie trafia na dysk, dopóki użytkownik go nie potwierdzi.

Co jest szyfrowane, a co nie

Przy włączonej ochronie hasłem szyfrowany jest cały rekord konta poza identyfikatorem i odciskiem — łącznie z nazwą usługi, więc skradziony profil nie zdradza, w jakich serwisach użytkownik ma konta. Włączenie ochrony szyfruje rekordy, weryfikuje je przez odszyfrowanie i porównanie, i dopiero potem usuwa wszystkie kopie jawne: z lokalnego magazynu przeglądarki, z synchronizacji i ze wszystkich siedmiu rotowanych migawek kopii zapasowych.

Mówimy wprost, bo to ma znaczenie przy ocenie:

  • Przy wyłączonej ochronie hasłem konta są przechowywane bez szyfrowania i — jeśli włączona jest synchronizacja Chrome — replikowane przez konto Google użytkownika. Do nas nigdy nie trafiają, ale ma je Google. Synchronizację można wyłączyć, co usuwa też to, co już się tam znalazło.
  • Historia użycia w rozbiciu na witryny — które konto jest używane na której domenie — jest przechowywana lokalnie i w trakcie zbierania nie jest objęta sejfem. Włączenie ochrony hasłem ją kasuje; można ją też wyłączyć osobno.

Model zagrożeń

Chroni przed

  • Kradzieżą lub skopiowaniem katalogu profilu przeglądarki
  • Złośliwym oprogramowaniem typu infostealer, które hurtowo wykrada dane przeglądarki
  • Osobą z fizycznym dostępem do pozostawionego bez nadzoru komputera
  • Trafieniem rekordów kont do Google przez synchronizację Chrome
  • Zgubieniem lub kradzieżą pliku kopii zapasowej (eksport chroniony hasłem)

Nie chroni przed

  • Złośliwym kodem działającym jako użytkownik, gdy sejf jest odblokowany
  • Keyloggerem przechwytującym hasło w trakcie wpisywania
  • Skompromitowaną przeglądarką lub systemem operacyjnym
  • Włamaniem do zewnętrznych serwisów, których dotyczą kody

Krótko: to chroni dane w spoczynku. Nie broni — i nie może obronić — urządzenia, które w trakcie używania jest już pod kontrolą atakującego.

Uprawnienia

Manifest deklaruje dokładnie dwa uprawnienia i żadnych uprawnień do hostów:

storage
Konta i ustawienia w magazynie lokalnym, odblokowany klucz w magazynie sesji oraz opcjonalna kopia do synchronizacji
activeTab
Odczytuje nazwę hosta aktywnej karty, żeby podświetlić pasujące konto, i przechwytuje kartę, gdy użytkownik skanuje kod QR z ekranu

Nie ma żadnych content scriptów, nie ma uprawnień tabs, cookies ani webRequest i nie ma zasobów dostępnych z sieci. Rozszerzenie nie może odczytać ani zmienić treści żadnej strony.

Kamera

Skanowanie QR kamerą działa na stronie rozszerzenia otwartej w karcie, a nie w okienku popup — popup jest niszczony, gdy traci fokus, a prośba o uprawnienie robi dokładnie to. Do tego nie jest potrzebne żadne uprawnienie w manifeście: używana jest standardowa prośba przeglądarki o dostęp do kamery, przyznawana dla origin rozszerzenia i odwoływalna w ustawieniach witryny, i nigdy nie pojawia się, zanim użytkownik nie otworzy skanera. Obraz jest dekodowany lokalnie, nigdy nie jest przesyłany ani zapisywany.

Ruch wychodzący

Przy normalnym użyciu rozszerzenie nie wykonuje żadnych automatycznych żądań, a Manifest V3 zakazuje zdalnego kodu. Wszystkie połączenia, jakie może nawiązać:

HostKiedyCzy przenosi dane użytkownika?
worldtimeapi.org
timeapi.io
Sprawdzenie rozjazdu zegara, buforowane, przy błędzie po cichu pomijane. Rozjechany zegar psuje TOTP.Nie
authenticator.shStrona powitalna przy instalacji; strona opinii przy odinstalowaniu lub ocenie.Nie (zwykłe logi serwera WWW)

Żadne fonty, skrypty, style ani obrazy nie ładują się z zewnętrznych hostów. Wszystko, co potrzebne do wyrenderowania interfejsu, jest w paczce.

Jak sprawdzić to, co publikujemy

Nic z powyższego nie trzeba przyjmować na wiarę. Rozszerzenie ma otwarty kod, a każde wydanie jest powtarzalne:

  1. Pobierz opublikowany plik .crx z Chrome Web Store i rozpakuj go
  2. Przełącz się na odpowiedni tag gita
  3. Uruchom npm ci && npm run build na Node 20 LTS
  4. Porównaj powstały dist/ z rozpakowaną paczką

Przy każdym wydaniu na GitHubie publikujemy SHA-256 dla każdego pliku w zbudowanym dist/, jako SHA256SUMS-v<version>.txt i w formacie sha256sum — dzięki temu krok 4 sprowadza się do jednego uruchomienia sha256sum -c. Różnice powinny ograniczać się do kolejności plików w archiwach i białych znaków w zminifikowanym wyniku między wersjami łatek Node.

Zależności w czasie działania są celowo nieliczne — OTPAuth, React, jsQR, Zustand, Framer Motion i Lucide — przypięte zacommitowanym plikiem lock. SBOM w formacie CycloneDX udostępniamy na życzenie.

Zobacz kod źródłowy

Czego nie mamy

Jesteśmy małym niezależnym dostawcą. Jeśli którykolwiek z poniższych punktów jest w waszym procesie wymogiem twardym, lepiej dowiedzieć się teraz niż po trzech tygodniach oceny:

  • Brak certyfikacji SOC 2, ISO 27001 ani równoważnej
  • Do tej pory nie zlecono zewnętrznego testu penetracyjnego
  • Brak płatnego programu bug bounty

W zamian oferujemy pełną jawność kodu, weryfikowalną kompilację, minimalny zestaw uprawnień i brak infrastruktury serwerowej, która w ogóle mogłaby przechowywać wasze dane.

Kontakt z nami

Zgłoszenia podatności i pytania o bezpieczeństwo: security@authenticator.sh. Polityka ujawniania, zakres, czasy reakcji i warunki safe harbour są na stronie polityki bezpieczeństwa; co jest przechowywane i co opuszcza urządzenie, opisuje polityka prywatności.

Chętnie wypełnimy pisemną ankietę oceny dostawcy albo przejdziemy przez kod razem z zespołem bezpieczeństwa.

We wszystkim, co nie dotyczy bezpieczeństwa — instalacja, odzyskiwanie konta, pytania o rozliczenia przy wdrożeniu — zajrzyj do pomocy. Prosimy nie wysyłać tam zgłoszeń podatności: ta skrzynka nie jest traktowana jako poufna.