Wir sind heute auf Product Hunt! Kommentar schreiben

Authenticator 1.16.0 ist da. Neuerungen ansehen

So funktioniert es

Ein technischer Überblick für Sicherheitsprüfer. Alles hier lässt sich am Quellcode nachprüfen — auch die weniger schmeichelhaften Punkte, die wir benennen statt wegzulassen.

Architektur

Die Erweiterung ist eine Manifest-V3-Chrome-Erweiterung, die TOTP-Codes lokal mit OTPAuth erzeugt. Das Erzeugen der Codes sowie das Speichern und Verschlüsseln der Konten kommen ohne Backend aus, und es gibt keine Nutzerkonten. Wir betreiben einen einzigen Server, api.authenticator.sh, für die kostenlose Version und Pro — unten beschrieben —, und er erhält nie einen geheimen Schlüssel, einen Kontonamen, einen Aussteller oder einen Code.

Dieser Server hält keinerlei Schlüsselmaterial zu den Konten der Nutzer: Es gibt keine Schlüsselhinterlegung und keinen von uns kontrollierten Wiederherstellungsweg. Wer sein Passwort vergisst und den Wiederherstellungscode verliert, dem können wir nicht helfen — so ist es beabsichtigt.

Kryptografie

Der Passwortschutz ist optional und standardmäßig aus. Ist er aktiv:

Verschlüsselung
AES-256-GCM, zufälliger 96-Bit-IV pro Datensatz und pro Neuschreiben
Schlüsselableitung
PBKDF2-HMAC-SHA256, 600.000 Iterationen, zufälliges 128-Bit-Salt (nach OWASP-Empfehlung)
Hauptschlüssel
256 Bit, aus crypto.getRandomValues, einmalig erzeugt; das Passwort umschließt ihn lediglich
Fingerabdrücke
HMAC-SHA256 unter einem per HKDF abgeleiteten Teilschlüssel, um Datensätze geräteübergreifend zusammenzuführen
Speicherung des entsperrten Schlüssels
chrome.storage.session — nur im Arbeitsspeicher, nie auf die Festplatte geschrieben, beim Schließen des Browsers gelöscht, für Content-Skripte unerreichbar
Automatische Sperre
Bei jedem Öffnen / nach 5, 15, 60 Minuten Inaktivität / bis der Browser schließt
Umsetzung
Ausschließlich WebCrypto. Kein Primitiv ist selbst gebaut, keine Krypto-Bibliothek wird mitgeliefert.

Warum zwei Schlüsselebenen

Daten werden nie direkt mit einem aus dem Passwort abgeleiteten Schlüssel verschlüsselt. Ein zufälliger Hauptschlüssel verschlüsselt die Datensätze; die PBKDF2-Ausgabe umschließt nur diesen Hauptschlüssel. Daraus folgen zwei Dinge, und beide zählen:

  • Ein Passwortwechsel schreibt 32 Byte neu, statt jeden Datensatz, jedes Backup und jeden Export neu zu verschlüsseln. Genau bei solchen Massenschreibvorgängen verlieren Speichersysteme Daten.
  • Ein 160-Bit-Wiederherstellungscode kann denselben Hauptschlüssel unabhängig umschließen, ein vergessenes Passwort ist also kein Totalverlust. Der Code wird einmal angezeigt, muss zur Bestätigung erneut eingegeben werden und wird nach jeder Verwendung erneuert. Nichts wird auf die Festplatte geschrieben, bevor der Nutzer ihn bestätigt hat.

Was verschlüsselt wird — und was nicht

Bei aktivem Passwortschutz wird der gesamte Kontodatensatz verschlüsselt, bis auf Kennung und Fingerabdruck — auch der Dienstname, damit ein gestohlenes Profil nicht verrät, bei welchen Diensten jemand Konten hat. Beim Aktivieren werden die Datensätze verschlüsselt, durch Entschlüsseln und Vergleichen geprüft und erst danach alle Klartextkopien entfernt: lokaler Browserspeicher, Sync und alle sieben rollierenden Backup-Stände.

Klar gesagt, weil es für Ihre Bewertung zählt:

  • Ohne Passwortschutz werden Konten unverschlüsselt gespeichert und, wenn Chrome Sync aktiv ist, über das Google-Konto des Nutzers repliziert. Zu uns gelangen sie nie, aber Google hält sie vor. Sync lässt sich abschalten, was auch das Vorhandene wieder entfernt.
  • Der seitenbezogene Nutzungsverlauf — welches Konto auf welcher Domain verwendet wird — liegt lokal und ist während der Erfassung nicht vom Tresor abgedeckt. Das Aktivieren des Passwortschutzes löscht ihn; er lässt sich auch unabhängig abschalten.

Bedrohungsmodell

Schützt gegen

  • Ein gestohlenes oder kopiertes Browser-Profilverzeichnis
  • Infostealer-Malware, die Browserdaten en bloc abzieht
  • Physischen Zugriff auf einen unbeaufsichtigten Rechner
  • Kontodatensätze, die über Chrome Sync zu Google gelangen
  • Eine verlorene oder gestohlene Backup-Datei (passwortgeschützter Export)

Schützt nicht gegen

  • Malware, die als der Nutzer läuft, während der Tresor entsperrt ist
  • Einen Keylogger, der das Passwort bei der Eingabe mitliest
  • Einen kompromittierten Browser oder ein kompromittiertes Betriebssystem
  • Die Kompromittierung der Drittdienste, für die die Codes gelten
  • Einen unverschlüsselten Export, den Sie selbst geschrieben haben — einfaches JSON, otpauth://-Links oder CXF sind für jeden lesbar, der die Datei öffnet

Kurz gesagt: Das schützt Daten im Ruhezustand. Ein Gerät, das während der Nutzung bereits unter der Kontrolle eines Angreifers steht, schützt es nicht — und kann es nicht.

Berechtigungen

Das Manifest deklariert fünf Berechtigungen und keine Host-Berechtigungen:

storage
Konten und Einstellungen im lokalen Speicher, der entsperrte Schlüssel im Session Storage und die optionale Sync-Kopie
activeTab
Liest den Hostnamen des aktiven Tabs, um das passende Konto hervorzuheben, und erfasst den Tab, wenn ein QR-Code vom Bildschirm gescannt wird
contextMenus
Fügt den Eintrag „2FA-Code einfügen“ zum Rechtsklick-Menü hinzu, und nur auf bearbeitbaren Feldern auf http(s)-Seiten
scripting
Injiziert die eine Funktion, die den Code ins Feld schreibt — für einen einzigen Tab und einen einzigen Aufruf, erst nachdem dieser Menüeintrag gewählt wurde
sidePanel
Öffnet Chromes Seitenleiste, wenn die App dort geöffnet werden soll — das gewährt keinerlei Zugriff auf Seiteninhalte

Es gibt keine Content-Skripte, keine Berechtigungen für tabs, cookies oder webRequest und keine web-accessible resources. Nichts von uns existiert in einer Seite, bis Sie dort einen Code anfordern; was dann läuft, wird für genau diesen Tab und diesen einen Aufruf injiziert, unter der Freigabe, die Ihr eigener Klick erteilt, und hinterlässt nichts.

Kamera

Das QR-Scannen per Kamera läuft auf einer Erweiterungsseite in einem Tab, nicht im Popup — ein Popup wird zerstört, sobald es den Fokus verliert, und genau das tut eine Berechtigungsabfrage. Dafür ist keine Manifest-Berechtigung nötig: Es nutzt die Standard-Kameraabfrage des Browsers, erteilt pro Erweiterungs-Origin und in den Website-Einstellungen widerrufbar, und sie erscheint erst, wenn der Scanner geöffnet wird. Das Video wird lokal dekodiert und nie übertragen oder gespeichert.

Kostenlose Version, Pro und der tägliche Abgleich

Seit 1.14.0 meldet sich die Erweiterung einmal täglich bei api.authenticator.sh — beim Browserstart oder nachdem das Popup gerendert wurde, nie auf dem Weg zur Anzeige eines Codes. Die Anfrage ist eine geschlossene Liste von Feldern, wird in einer einzigen Funktion in src/billing/sync.ts zusammengesetzt und durch einen Test auf genau diese Liste festgelegt:

iid
Eine zufällige ID, die diese Installation erzeugt hat. Nicht mit einem Google-Konto, einer E-Mail-Adresse oder dem Browser verknüpft — außer beim Kauf von Pro: Dann verknüpft der Kaufdatensatz die Installation, aus der gekauft wurde, und jede Installation, auf der der Lizenzschlüssel aktiv ist, mit der E-Mail-Adresse, mit der bezahlt wurde
ver, ui_lang, browser_lang
Version der Erweiterung, Sprache der Oberfläche, Sprache des Browsers
installed_at, legacy, legacy_src
Wann die Installation entstanden ist und ob sie aus der Zeit vor Einführung der Abrechnung stammt
accounts, groups
Wie viele Konten sie enthält und in wie vielen Gruppen — Zahlen, nie welche Konten und nie die Gruppennamen
vault, sync, open_mode, view_mode, style, dark, os
Ob Passwortschutz und Sync aktiv sind und wie sich die Erweiterung öffnet, wie die Kontoliste angezeigt wird (normal, kompakt oder mit verborgenen Codes), sowie welcher Stil gewählt ist, hell oder dunkel, und das Betriebssystem (Windows, macOS, Linux, ChromeOS)
pid, lid, has_key, key_hint
Welche signierte Richtlinie und welche Lizenz die Installation gerade hat, ob sie den Lizenzschlüssel schon hat und die letzten vier Zeichen dieses Schlüssels
opens
Wie oft die Erweiterung an jedem Tag seit dem letzten Abgleich geöffnet wurde (höchstens die letzten 14 Tage) — eine Zahl pro Tag, nichts darüber, was angesehen wurde
events
Zwischengespeicherte Abrechnungsereignisse aus einer geschlossenen Liste: Das Limit wurde erreicht, die Paywall angezeigt oder geschlossen, ein Tarif gewählt, ein Bezahlvorgang oder ein Schlüssel versucht

Nie gesendet: geheime Schlüssel, Kontonamen, Aussteller, Codes oder die Websites, auf denen sie verwendet werden. Der Server ermittelt das Land aus der Anfrage an seinem Edge und speichert die IP-Adresse nicht. Die Deinstallationsseite erhält dieselbe Installations-ID als ?i=: Sie meldet dem Server, dass die Installation entfernt wurde, und ordnet ihr eine freiwillige Antwort auf die Umfrage zu.

Dafür liegt in chrome.storage.local: die Installations-ID, die zuletzt erhaltene signierte Richtlinie und Lizenz, der Lizenzschlüssel dieser Installation (eingegeben oder nach einem Kauf auf ihr erhalten), die Zahl der Öffnungen pro Tag, bis der Server sie hat, sowie die zwischengespeicherten Ereignisse — keine Kontodaten. Ist Sync aktiv, landen außerdem die Angabe, ob die Installation aus der Zeit vor der Abrechnung stammt, und dieser Lizenzschlüssel in Chrome Sync, damit die anderen Chrome-Profile des Nutzers sie übernehmen und Pro von selbst einschalten; wird Sync ausgeschaltet, verschwinden beide aus Chrome Sync, wird es wieder eingeschaltet, kommen sie zurück.

Was zurückkommt und wie die Erweiterung damit umgeht:

Tokens
Die Richtlinie (das Kontolimit der kostenlosen Version) und die Lizenz (Pro) sind JWS, signiert mit ES256 (ECDSA P-256)
Prüfung
WebCrypto, gegen die in den Build einkompilierten öffentlichen Schlüssel (src/billing/keys.ts). Ein Build für den Chrome Web Store vertraut nur dem Produktionsschlüssel, und die Build-Prüfung weist einen Build zurück, der irgendeinen anderen enthält
Offline
Limit und Lizenz werden lokal geprüft, anhand der zuletzt erhaltenen signierten Tokens. Solange noch keine signierte Richtlinie empfangen wurde, ist nichts begrenzt — ein unerreichbarer Server kann niemanden aussperren
Was das Limit bewirken kann
Verhindern, dass ein Konto hinzugefügt wird, und sonst nichts. Es kann kein Konto verbergen, sperren, entfernen oder verändern und weder Codes noch Export, Backups, Wiederherstellung oder Sync blockieren
Käufe
Stripe Checkout in einem neuen Tab, mit Link als Verkäufer (Merchant of Record). Die E-Mail-Adresse des Käufers erreicht uns über Stripe, damit wir den Lizenzschlüssel ausstellen und wiederherstellen können; Schlüssel werden als Hash gespeichert, dazu eine verschlüsselte Kopie, damit ein verlorener Schlüssel erneut verschickt werden kann
Lizenzschlüssel
Die Antwort auf den Abgleich enthält den Schlüssel selbst nur für die Installation, auf der Pro gekauft wurde, und nur so lange, bis die vier Zeichen, die sie in key_hint meldet, zu diesem Schlüssel passen — so ersetzt ein später gekaufter Schlüssel einen älteren; eine Installation, in die der Schlüssel eingegeben wurde, bekommt nie einen geschickt

Das Limit ist kein DRM: Der Code ist Open Source, und ein Fork kann es entfernen. Was niemals möglich sein darf: dass jemand die Lizenz einer anderen Person erlangt oder nutzt oder die Installation eines anderen begrenzt — das wäre eine Schwachstelle und fällt in den Geltungsbereich unserer Sicherheitsrichtlinie.

Ausgehender Netzwerkverkehr

Zwei Arten von Anfragen stellt die Erweiterung von sich aus: die Uhrzeitprüfung und den täglichen Abgleich für die Abrechnung. Alles Weitere unten geschieht, weil der Nutzer darauf geklickt hat. Manifest V3 verbietet Remote-Code, und nichts davon transportiert Konten, geheime Schlüssel oder erzeugte Codes. Die vollständige Liste:

HostWannEnthält Nutzerdaten?
time.akamai.com
timeapi.io
cloudflare.com
Prüfung auf Uhrabweichung, zwischengespeichert; ist keine Quelle erreichbar, steht das in den Einstellungen. Bei falsch gehender Uhr bricht TOTP.Nein
authenticator.shWillkommensseite bei der Installation; Feedback-Seite bei der Deinstallation, mit der Installations-ID in der Adresse; Hilfe- und Supportseiten, wenn sie aus dem Popup geöffnet werden.Die Installations-ID, nur auf der Deinstallationsseite; sonst nein (gewöhnliche Webserver-Logs)
api.authenticator.shAbgleich für die Abrechnung einmal täglich; Aufrufe für Checkout, Lizenz und Kundenportal, wenn der Nutzer Pro kauft, einen Schlüssel eingibt, einen Kauf wiederherstellt oder ein Abo verwaltet.Die oben aufgeführten Felder — nie Kontodaten. Einen Lizenzschlüssel oder eine E-Mail-Adresse nur, wenn der Nutzer sie selbst eingibt
checkout.stripe.com
billing.stripe.com
Stripe Checkout und Kundenportal, in einem Tab geöffnet, wenn der Nutzer Pro kauft oder ein Abo verwaltet.Was der Käufer dort eingibt. Es gelten die eigenen Bedingungen von Stripe und Link
chromewebstore.google.comStore-Eintrag, nur per Klick in einem Tab geöffnet: das Bewertungsformular aus der Bewertungsabfrage.Nein (für Google ist es der Aufruf einer Store-Seite wie jeder andere)

Weder Schriften noch Skripte, Styles oder Bilder werden von Drittanbieter-Hosts geladen. Alles, was die Oberfläche zum Rendern braucht, steckt im Paket.

Überprüfen, was wir veröffentlichen

Sie müssen nichts davon glauben. Die Erweiterung ist quelloffen, und jedes Release ist reproduzierbar:

  1. Die veröffentlichte .crx aus dem Chrome Web Store herunterladen und entpacken
  2. Den passenden Git-Tag auschecken
  3. npm ci && npm run build unter Node 20 LTS ausführen
  4. Das entstandene dist/ mit dem entpackten Paket vergleichen

Für jede Datei im erzeugten dist/ wird mit jedem GitHub-Release ein SHA-256 als SHA256SUMS-v<version>.txt veröffentlicht, im Format sha256sum — Schritt 4 ist damit ein einziger Aufruf von sha256sum -c. Abweichungen sollten sich auf die Dateireihenfolge in Archiven und Leerzeichen in minifizierter Ausgabe zwischen Node-Patch-Versionen beschränken.

Die Laufzeitabhängigkeiten sind bewusst wenige — OTPAuth, React, jsQR, Zustand, Framer Motion und Lucide — festgehalten durch eine eingecheckte Lockfile. Eine CycloneDX-SBOM stellen wir auf Anfrage bereit.

Quellcode ansehen

Was wir nicht haben

Wir sind ein kleiner unabhängiger Anbieter. Wenn eines der folgenden Dinge für Ihren Prozess zwingend ist, erfahren Sie es besser jetzt als drei Wochen später in der Bewertung:

  • Keine Zertifizierung nach SOC 2, ISO 27001 oder Vergleichbarem
  • Bis heute kein beauftragter externer Penetrationstest
  • Kein bezahltes Bug-Bounty-Programm

Was wir stattdessen bieten: vollständige Transparenz des Quellcodes, einen verifizierbaren Build, eine minimale Berechtigungsfläche und einen Server, an den Ihre geheimen Schlüssel, Kontonamen oder Codes gar nicht erst gesendet werden.

Kontakt

Schwachstellenmeldungen und Sicherheitsfragen: security@authenticator.sh. Offenlegungsrichtlinie, Geltungsbereich, Reaktionszeiten und Safe-Harbour-Bedingungen stehen auf der Seite Sicherheitsrichtlinie; was gespeichert wird und was das Gerät verlässt, steht in der Datenschutzerklärung.

Wir beantworten gerne einen schriftlichen Lieferantenfragebogen oder gehen den Code mit einem Sicherheitsteam durch.

Für alles, was keine Sicherheitsfrage ist — Installation, Kontowiederherstellung, Abrechnungsfragen aus einem Rollout — siehe Support. Bitte schicken Sie dorthin keine Schwachstellenmeldungen; dieses Postfach gilt nicht als vertraulich.