5分間の監査

Vaultedのzero-knowledge暗号化を自分で確認する

セキュリティツールを信頼するだけでなく — 検証しよう。4つのブラウザテスト、インストール不要、5分間。

60秒チェックリスト

まずこれをざっと確認しよう。下の詳細ウォークスルーで各ステップを詳しく説明している。

  1. 1

    DevToolsを開く → Networkタブ

    Vaultedで Cmd+Option+I(macOS)または F12(Windows/Linux)を押す。Networkタブに切り替えてFetch/XHRでフィルタリングする。

  2. 2

    シークレットを作成してPOSTを確認

    わかりやすいカナリア文字列(例: CANARY-12345)を入力してCreateをクリック。POST /api/secrets リクエストを見つける。Payloadタブを開くと、暗号文(base64)とivのみが表示される。ボディ内でカナリアを検索しても — 見つからない。

  3. 3

    共有リンクを確認

    生成されたリンクを見よう。復号キーは#(URLフラグメント)の後にある。RFC 3986に従い、ブラウザはフラグメントをサーバーに送らない — リクエストライン、ヘッダー、リファラーのいずれにも含まれない。

  4. 4

    復号がクライアントサイドで実行されることを確認

    新しいタブでリンクを開く。/api/secrets/[id]からのGETレスポンスには暗号文のみが含まれる。Sourcesパネルで crypto.subtle.decrypt を検索すると — その呼び出しはサーバーではなくブラウザ上で実行されている。

何を検証するか

Vaultedの主張は具体的だ: サーバーは平文も暗号化キーも見ることはない。 これは4つの観察可能な特性に分解できる:

  1. 平文はどのネットワークリクエストにも現れない。
  2. 暗号化キーはどのネットワークリクエストにも現れない。
  3. URLフラグメント(キーが存在する場所)はサーバーに届かない。
  4. サーバーサイドのデータだけではシークレットを再構築できない。

4つすべてが成り立てば、アーキテクチャは構造的にzero-knowledge — マーケティング用語は不要だ。

テスト 1平文はネットワークを通過しない

  1. vaulted.fyi を開く。
  2. DevToolsを開いて Network タブに切り替える。Fetch/XHR でフィルタリングする。
  3. シークレットフィールドにわかりやすい文字列を入力する — 例えば CANARY-12345
  4. Create をクリックする。

単一の POST リクエストが /api/secrets に表示される。それをクリックして Payload タブを確認する。

ボディには ciphertext フィールドと iv フィールドが含まれている。どちらもbase64urlエンコードされたblobだ。ペイロードで CANARY-12345 を検索しても — 見つからない。平文はリクエストが送信される前にブラウザ内で暗号化された。

念を入れたい場合は、ネットワークスロットリングを「Slow 3G」に設定して繰り返す。暗号文は引き続きノイズのように見え、平文はどこにも見当たらない。

テスト 2キーもネットワークを通過しない

シークレットを作成すると、Vaultedは共有リンクを表示する。こんな形だ:

https://vaulted.fyi/s/abc123#dGhpcyBpcyBhIGtleQ
                              ^^^^^^^^^^^^^^^^^^^^
                              encryption key (base64url)

# の後の部分がURLフラグメントだ。RFC 3986 に従い、ブラウザはフラグメントをローカルで処理する — HTTPリクエストライン、ヘッダー、リファラーには現れない。

これを証明するには:

  1. 共有リンクをコピーする。
  2. DevToolsのNetworkタブを開いた状態で新しいタブで開く。
  3. GET /s/abc123 リクエストを見つける。
  4. Headers タブを確認する — 完全なリクエストURL、フラグメントなし。
  5. Request タブを確認する — フラグメントなし。
  6. 次のページで document.referrer を確認する — フラグメントは除去されている。

受信者がシークレットを復号するために必要なキーはURLの中にあったが、そのブラウザ内に留まった。サーバーが見たのは GET /s/abc123 のみだ。

テスト 3サーバー単独では復号できない

ターミナルを開いて、curl でシークレットを直接取得する:

curl https://vaulted.fyi/api/secrets/abc123

ciphertextiv を含むJSONが返ってくる。これがシークレットのサーバーサイドの完全な状態だ。

これを解読しようとしてみよう。URLフラグメントのキーなしでは無理だ。適切に生成されたランダムキーによるAES-256-GCMは、実用的な観点からランダムノイズと区別できない。Vaultedのサーバーからの完全なデータベースダンプでも、得られるのは暗号化されたblobとメタデータだけだ。

これがzero-knowledgeの文字通りの定義だ:サーバーは読めないデータを保存している。

テスト 4暗号化は見えるJavaScriptで実行される

Vaultedは Web Crypto API を使っている。これはブラウザのプリミティブで、難読化されたWASMやネイティブモジュールで処理を隠してはいない。暗号化が行われる様子を直接観察できる。

  1. DevToolsで Sources タブを開く。
  2. crypto.subtle.encrypt を検索する(グローバル検索には Cmd+Option+F を使う)。
  3. crypto.subtle.encrypt を呼び出す行にブレークポイントを設定する。
  4. 新しいシークレットの作成をトリガーする。
  5. ブレークポイントが当たる。引数を確認すると:平文が Uint8Array として、AES-GCMキー、フレッシュなランダムIVが見える。
  6. 呼び出しをステップオーバーする。結果が送信される暗号文だ。

ネットワークリクエストの前に、ブラウザ内で平文が暗号文になる様子をリアルタイムで観察している。データが通る他の経路はない。

これが証明すること

  • 平文はブラウザの外に出ない。 テスト1。
  • キーはブラウザの外に出ない。 テスト2。
  • サーバーは保存しているデータで復号できない。 テスト3。
  • 暗号化は本物でクライアントサイドで実行される。 テスト4。

これがzero-knowledgeの主張の全体であり、5分間で稼働中の本番システムに対して実証された。

これが証明しないこと

検証は誠実な作業だ — その限界について明確にしておく価値がある。

  • テストはこの瞬間の動作を証明する。 将来のコード変更がこの特性を破る可能性がある。継続的な保証が必要な場合は、changelog を購読して定期的にテストを再実行しよう。
  • デバイス自体に対しては保護できない。 キーロガーや悪意のあるブラウザ拡張機能は、復号後に平文を読むことができる。これはどのWebアプリの制御範囲外だ。
  • 実行したJavaScriptがVaultedが配信するJavaScriptであることを前提としている。 CDNを侵害した標的型攻撃者は、特定ユーザーに異なるバンドルを配信できる可能性がある。Subresource Integrityと再現可能ビルドでこれを軽減できる。詳細は 脅威モデル を参照。

さらに深く掘り下げる

より詳しく調べたい場合:

セキュリティツールに対する最も強力な論拠はそのマーケティングではない。分解して、主張通りの動作をすることを確認できることだ。Vaultedはそれができるように設計されている。

よくある質問

質問や問題を発見した場合は [email protected] にメールしよう — 責任ある開示ポリシー を公開しており、48時間以内に返答する。