本日 Product Hunt に掲載中です! コメントを書く
Authenticator 1.16.0 をリリースしました。 変更点を見る
セキュリティを評価する方に向けた技術概要です。ここに書かれていることはすべてソースコードで確認できます。都合の悪い点も省かずに明記しています。
本拡張機能は Manifest V3 の Chrome 拡張機能で、TOTP コードを OTPAuth を使ってローカルで生成します。コードの生成、アカウントの保存と暗号化にバックエンドは関与せず、ユーザー登録の仕組みもありません。当方が運用するサーバーは、無料プランと Pro のための api.authenticator.sh の一つだけで(後述)、このサーバーが秘密鍵、アカウント名、発行元、コードを受け取ることは決してありません。
このサーバーは、誰のアカウントについても鍵素材を保持しません。鍵の預託も、当方が管理する復旧手段もありません。パスワードを忘れ、リカバリーコードも失った場合、当方にできることはありません。これは設計上の選択です。
パスワード保護は任意で、既定では無効です。有効にした場合:
データをパスワード由来の鍵で直接暗号化することはありません。レコードを暗号化するのはランダムなマスターキーで、PBKDF2 の出力はそのマスターキーを包むだけです。ここから二つの結果が生まれ、どちらも重要です:
パスワード保護を有効にすると、識別子とフィンガープリントを除くアカウントレコード全体が暗号化されます。サービス名も対象なので、プロファイルを盗まれても、その人がどのサービスにアカウントを持っているかは分かりません。有効化の際は、レコードを暗号化し、復号して突き合わせることで検証したうえで、初めて平文のコピーをすべて削除します。ブラウザーのローカルストレージ、同期、そして 7 世代のローテーションバックアップのすべてが対象です。
評価に関わる点なので、率直に記します:
要するに、これが守るのは保存状態のデータです。使用中の時点ですでに攻撃者の制御下にある端末を守ることはできませんし、できるとも言いません。
マニフェストが宣言する権限は五つで、ホスト権限はありません:
コンテンツスクリプトは一切なく、tabs・cookies・webRequest の権限、web-accessible resources のいずれもありません。あなたがそのページでコードを求めるまで、私たちのものは何一つページに存在しません。そのとき動くものは、その一つのタブとその一回の呼び出しのために、あなた自身のクリックが与える許可のもとで注入され、あとには何も残りません。
カメラによる QR 読み取りは、ポップアップではなくタブで開いた拡張機能ページ上で動作します。ポップアップはフォーカスを失うと破棄され、権限ダイアログはまさにそれを引き起こすからです。これにはマニフェスト上の権限は不要です。ブラウザー標準のカメラ許可ダイアログを使い、拡張機能のオリジン単位で付与され、サイトの設定から取り消せます。スキャナーを開くまで要求されることはありません。映像はローカルでデコードされ、送信も保存も一切されません。
1.14.0 以降、拡張機能は 1 日 1 回 api.authenticator.sh と通信します。タイミングはブラウザーの起動時か、ポップアップの描画が終わった後で、コードを表示するまでの処理の途中で行うことはありません。リクエストは項目が固定された閉じた一覧で、src/billing/sync.ts 内の一つの関数で組み立てられ、テストによってその一覧に保たれています:
送信しないもの:秘密鍵、アカウント名、発行元、コード、それらを使うサイト。国はサーバーがエッジでリクエストから取得し、IP アドレスは保存しません。アンインストール時のページは同じインストール ID を ?i= として受け取り、そのインストールが削除されたことをサーバーに伝え、任意のアンケートの回答もそのインストールと結び付けます。
このために chrome.storage.local に保存するのは、インストール ID、最後に受け取った署名付きのポリシーとライセンス、このインストールが保持するライセンスキー(入力されたもの、またはこのインストールで購入したあとに受け取ったもの)、サーバーが受け取るまでの日ごとの開いた回数、送信待ちのイベントで、アカウントのデータは含みません。同期が有効な間は、インストールが課金の導入より前かどうかと、そのライセンスキーも Chrome 同期に保存され、利用者のほかの Chrome プロファイルに引き継がれて Pro が自動で有効になります。同期をオフにすると両方とも Chrome 同期から削除され、オンに戻すと再び保存されます。
返ってくるものと、拡張機能での扱い:
この上限は DRM ではありません。コードはオープンソースで、フォークすれば取り除けます。決してあってはならないのは、ある人が他人のライセンスを入手・使用できること、あるいは他人のインストールに制限をかけられることです。それは脆弱性であり、当方のセキュリティポリシーの対象範囲に含まれます。
自分から行う通信は、時刻の確認と課金のための 1 日 1 回の通信の二種類です。以下のそれ以外はすべて利用者がクリックした結果として発生します。Manifest V3 はリモートコードを禁じており、ここに挙げたもののいずれもアカウント・秘密鍵・生成されたコードを運びません。全一覧は次のとおりです:
| ホスト | タイミング | 利用者データを含むか |
|---|---|---|
| time.akamai.com timeapi.io cloudflare.com | 時刻のずれの確認。キャッシュあり。どの取得先にも届かない場合は設定にその旨が表示されます。時刻がずれると TOTP は成立しません。 | 含まない |
| authenticator.sh | インストール時のようこそページ、アンインストール時のフィードバックページ(アドレスにインストール ID を含む)、ポップアップから開いたときのヘルプ・サポートページ。 | アンインストール時のページに限りインストール ID を含む。それ以外は含まない(通常の Web サーバーログのみ) |
| api.authenticator.sh | 1 日 1 回の課金のための通信。加えて、利用者が Pro を購入する、キーを入力する、購入を復元する、サブスクリプションを管理するときの決済・ライセンス・ポータル関連の呼び出し。 | 上に挙げた項目のみで、アカウントのデータは一切含まない。ライセンスキーやメールアドレスは、利用者が入力したときに限る |
| checkout.stripe.com billing.stripe.com | Stripe Checkout とカスタマーポータル。利用者が Pro を購入するか、サブスクリプションを管理するときにタブで開きます。 | 購入者がそこで入力した内容。Stripe と Link それぞれの規約が適用されます |
| chromewebstore.google.com | ストアの掲載ページ。クリックしたときだけタブで開きます。評価の案内からはレビュー欄。 | 含まない(Google からは通常のストアページ閲覧と同じに見えます) |
フォント・スクリプト・スタイル・画像のいずれも第三者ホストからは読み込みません。画面表示に必要なものはすべてパッケージ内に同梱されています。
以上のどれも、こちらを信用して受け入れる必要はありません。本拡張機能はオープンソースで、各リリースは再現可能です:
.crx をダウンロードして展開するnpm ci && npm run build を実行するdist/ と展開したパッケージを比較する生成された dist/ 内の全ファイルの SHA-256 を、各 GitHub リリースに SHA256SUMS-v<version>.txt として sha256sum 形式で添付しています。したがって手順 4 は sha256sum -c を一度実行するだけで済みます。差分はアーカイブ内のファイル順序と、Node のパッチバージョン差による minify 出力の空白に限られるはずです。
実行時の依存は意図的に少なく、OTPAuth・React・jsQR・Zustand・Framer Motion・Lucide のみで、コミット済みのロックファイルで固定しています。CycloneDX 形式の SBOM はご要望に応じて提供します。
ソースコードを見る当方は小規模な独立ベンダーです。次のいずれかが貴組織の必須要件であれば、評価を三週間進めた後よりも今知っていただくほうが良いはずです:
その代わりに提供できるのは、ソースコードの完全な公開、検証可能なビルド、最小限の権限、そしてそもそも秘密鍵・アカウント名・コードが一切送られてこないサーバーです。
脆弱性の報告およびセキュリティに関するお問い合わせは security@authenticator.sh まで。開示ポリシー、対象範囲、応答時間、セーフハーバー条項はセキュリティポリシーのページに、何が保存され何が端末の外に出るのかはプライバシーポリシーに記載しています。
書面のベンダー評価アンケートへの回答や、セキュリティチームとのコードの読み合わせにも喜んで応じます。
セキュリティ以外の件(インストール、アカウントの復旧、導入に伴う請求関連など)はサポートをご覧ください。脆弱性の報告をそちらに送るのはお控えください。あの窓口は機密として扱っていません。