Termiyo

セキュリティ

保管庫のしくみ

ぼかしません。実際に使っている構成と、そのパラメーター、そしてなぜそれを選んだかを書きます。

何から守るのか

以下のすべての判断は、三つの状況から決まっています。あなたのデータを保管し、それを決して読めてはならない同期サーバー。盗まれたノート PC、つまりデータベースファイルが他人の手にある状態。そしてそのファイルを手元に持ち、ハードウェアの許すかぎり速く推測を試す攻撃者。

鍵導出を決めるのは三つめです。速度を決めるのがあなたのパスワードではなく攻撃者の予算である、唯一の状況だからです。

二要素認証と、それが守るもの

二要素認証が守るのはアカウントであって、ボールトではありません。この違いは、聞こえる以上に大きな意味を持ちます。盗まれた、あるいは推測されたパスワードだけでは、新しい端末をサインインさせて封印済みの鍵一式を取り出すことができなくなります。暗号化された束と、その束を開く鍵も同じパスワードから作られる以上、中身のすべてが対象です。コードが実際に食い止めるのは、この攻撃です。

一方で、誰かの手元にあるマシンでボールトを開くには、そのパスワードだけで足ります。ボールトはここで、あなた自身のディスク上で暗号化されていて、何かを尋ねるサーバーは間に入っていません。つまり、そこにコードが守るものはありません。二要素認証は、すでにサインインしている端末をサインアウトさせることもなく、忘れたパスワードを取り戻せるようにもしません。

有効にすると、リカバリーコードが10個、一度だけ表示されます。それらと、サインインしたままのマシン — そのマシンではパスワードで要素を無効にできます。認証アプリを失くしたときに戻る道は、この二つです。三つ目はありません。こちらの誰かが要素を素通りさせることはできません。それを可能にするものが、私たちの側に存在しないからです。

Argon2id、速いハッシュではなく

マスターパスワードは Argon2id で 32-byte の鍵に伸ばされます。メモリ 64 MiB、3 パスで、libsodium の `crypto_pwhash` を使い、Argon2id を単一レーンで実行します。要点はメモリです。GPU は膨大な数のハッシュ演算を並列に走らせられますが、その一つ一つに 64 MiB の高速メモリを与えることはできません。これが幅の広い並列攻撃を、また狭い攻撃へ戻します。

比較として、1000 回反復の PBKDF2-SHA256 による導出 — いまでもよくある既定値です — は、攻撃者にとって 1 推測あたり 1 ミリ秒未満で、ほぼ完全に並列化できます。このパラメーターの Argon2id はノート PC で約 130 ms かかり、まさにその並列化に抵抗します。

パラメーターは保管庫と並べて記録されるので、後で引き上げても影響するのは新しい導出だけで、既存の保管庫はそのまま開きます。

レコードは一つずつ封じる

保管庫にはそれぞれ自分のランダムな 32-byte 鍵があり、マスター鍵の下に包まれます。レコードは XChaCha20-Poly1305 で、毎回新しい 24-byte のノンスを使って暗号化され、レコード自身の同一性 — 種類、所属する保管庫、id — が associated data として結び付けられます。

この最後の点は、聞こえるより重要です。これがないと、暗号文を持つ者が有効な暗号化ブロックを別のレコードへ移すことができ、クライアントはそれを受け入れてしまいます。これがあると、付け替えられたレコードはただ開きません。

鍵を渡さずに共有する

アカウントごとに X25519 の鍵ペアがあります。保管庫を共有すると、その鍵は相手の公開鍵に対して封じられます。ですからサーバーは「誰が何にアクセスできるか」を取り持ちながら、何かを開ける鍵を一度も持ちません。

アクセスの取り消しは、封じた複製を削除し、同期を止めます。相手がすでに持っているものには届きません。すでにデータを読んだ人は読んだままで、どんな仕組みもそれを取り消せません。取り消しは保管庫の鍵も変えません(Termiyo にはそれができません)。そのため、「編集可」だった間に同期した人は、この保管庫にあとから保存されるものをすべて開ける鍵を持ち続けます。そうしたレコードがどこから届いても同じで、その人と保管庫をもう一度共有すれば、「読み取り専用」であっても、少なくともホストは送られます。秘密を取り戻す方法は、サーバー側でパスワードと鍵を変えることです。

ホスト鍵は固定

Termiyo はサーバーを初めて見たとき、その鍵と SHA-256 フィンガープリントを表示し、あなたが受け入れたものを固定します。再接続のたびにその固定値と照合されます。

鍵が変わったとき、Termiyo は隠さずはっきり言います。作り直されたサーバーと割り込まれた接続は、ソフトウェアには同じに見えます。どちらを期待していたかを知っているのはあなただけです。

秘密が実際にある場所

接続はインターフェースとは別のプロセスで動きます。ターミナルを描く側のウィンドウは、ネットワークにもファイルシステムにもアクセスできず、パスワードや秘密鍵を受け取ることもありません。保存済みホストへ名前で接続するよう頼むだけで、それが何を意味するかは別のプロセスが決めます。

インターフェースに表示されるものは、その前に伏せられています。伏せられた項目のまま レコードを保存し直しても、保存されている秘密には触れません。

ダウンロードしたものを検証する

検査は 2 種類あり、答える問いが違います。ダウンロードページの各項目に並ぶ SHA-256 は、手元のバイト列が当社がビルドしたバイト列であることを示します。macOS と Linux では `shasum -a 256 <file>`、Windows では `certutil -hashfile <file> SHA256` です。

署名は誰がビルドしたかを示し、アプリを動かす前に OS が代わりに検査します。先に自分で確かめることもできます。macOS では `spctl -a -t open --context context:primary-signature -vv <file>.dmg` が "accepted" と "source=Notarized Developer ID" を返すはずです。

Windows のインストーラーは未署名なので、プロパティに[デジタル署名]タブはありません。タブがないことだけでは、ファイルが改変されたかどうかは分かりません。インストーラーを実行せずに保存してから、`certutil -hashfile "<file>" SHA256` を実行してください。`<file>` は保存したファイルのパスに置き換えます。インストーラーを開く前に、結果をダウンロードページの同じファイルの横にある SHA-256 と照合してください。一致しなければ実行しないでください。ハッシュの一致は、バイト列が当社の公開ファイルと同じであることを確認するもので、発行元の署名ではありません。下にある Linux の話と違って、これはプラットフォームの性質ではなく当社側の欠けです。Windows は署名をきちんと検査します。検査させる署名を当社がまだ用意していないだけです。ダウンロードしたインストーラーがご自身で検査できる署名を実際に持つまで、このページはそう書き続けます。

Linux に相当するものはありません。.deb も AppImage も、OS が検査する署名を持ちません。ですから検証できるのはハッシュだけです。これは当社の選択ではなくプラットフォームの性質であり、そうでないと思い込むより知っておくほうがよいことです。

あなたのマシンから出ていくもの

二つあり、どちらもここに並べてあります。Termiyo は 24 時間に最大 1 回、自分自身についての短い報告を送ります。バージョン、プラットフォーム、プロセッサ、インストール方法、インターフェースの言語、更新確認が有効かどうか、そして自身のフォルダーにあるクラッシュダンプの数です。識別子は付かず、セッションの中身も入りません。既定で有効で、初回起動時でも「設定 → ヘルプ」でも、クリック 1 回で切れます。もう一つはクラッシュ時のダンプで、あなた自身のディスク上のフォルダーに書かれます。それを私たちに送るかどうかは別のスイッチで、あなたが入れるまで切れたままです。「設定 → ヘルプ」がその場所を示し、ダンプに何が入り得るのかを説明し、フォルダーを開きます。

それを私たちに送るかどうかは、その画面のスイッチです。新規インストールでは切ってあり、更新しても切ったままで、切っているあいだはどのダンプもこのマシンから出ません。自分でバグ報告に添えるのが、いまも唯一の道です。有効にすると、「Termiyo の起動時に更新を確認する」がオンの場合に限り、次のクラッシュのダンプを HTTPS で送ります。一緒に送られるのは、あなたのマシンがそのファイルに付けた名前、バージョン、プラットフォーム、プロセッサのアーキテクチャ、そしてその最初の送信時に作られるこのインストールの識別子だけです。同じ画面が送ったものを一覧し、それを削除するよう私たちのサーバーに依頼するボタンを備えています。この段落はこれまで、クラッシュレポートは既定で無効なのではなく存在しないと書いていました。アップロード先を追加したビルドより前のすべてについて、それは真でした。詳細はプライバシーのページにあります。更新確認を切っている間は、送信に同意したダンプもこのマシンで待ち、確認を再びオンにしたあとの最初の起動で送られます。

更新確認を切っていれば、更新のライブラリは読み込まれません。ライブラリは最初に必要になった時点で import されるので、確認を切っていればモジュールはそこに存在せず、通信を行う手段を何も持ちません。ここまでは、コードの分岐についての約束ではなく、構造の話です。

ここは当社が間違っていた箇所であり、訂正します。以前ここには、確認を切っていれば起動時に外向きの通信は 1 件も出ないと書き、確かめる方法として tcpdump を挙げていました。確認を切っていれば、誰も触らない起動はいまは本当に静かです — Linux で、通信そのものを測って確かめました。しかし保管庫を開くと、更新確認の設定とは関係のない通信が始まり、このページはその一部しか挙げていませんでした。まず、開いたままにしたターミナルです。前回 Termiyo を閉じたときにまだ開いていた SSH タブは、保管庫が開くとすぐに開き直され、そのたびにホストへ改めて完全にログインします — 作業を離れたところに戻すための機能で、終了前に閉じたタブは自分からは戻りません。サインインしていないとき、アカウントの案内に答えるまでは、初回起動画面は termiyo.com が応答するかどうかを尋ねます。あなたにアカウントを提案する価値があるかどうかを知るためです — 起動ごとに 1 回、最初のロック解除のときです。termiyo.com に届かない間は案内を出さないので、次の起動でまた尋ねます。サインインしているとき、Termiyo はアドレスが確認済みかどうかを尋ねます — 起動ごとに一度、そしてまだ確認されていない間はもう一度。そのあとに表示される、コードを求めるパネルが答えを読み直すからです。保管庫が開くときに同期し、そのあとは 5 分ごとに同期します。ホスト・グループ・プロキシのフォームを開いたときには、それを保存できる保管庫を尋ねます。さらに自分の AI キーがなければ、AI パネルを開いたときやターミナルで入力を始めたときに、アカウントの AI 利用枠の残りを尋ねます。ホスト一覧が開いている間は、Termiyo が直接到達できる保存済みの SSH または telnet ホストすべてを 15 秒ごとに確かめます — そのポートに接続し、1 バイトも送らずに閉じるだけで、横の点を最新に保つためです。この接続は当社ではなくあなたのサーバーに向かい、そのサーバーのログに残ります。アドレスではなく名前で保存したホストなら、確かめるたびに DNS の問い合わせも 1 回加わり、それはあなたのマシンが使っているリゾルバーに向かいます。ホスト一覧を隠せばこの確認は止まりますが、同じ種類のものがもう一つあり、それは止まりません。前面のタブが、それらのホストのどれかに接続したターミナルである間は、ステータスバーが表示する遅延のために、同じ方法でそのホストを 10 秒ごとに確かめます。一覧があってもなくても、ステータスバーに「接続済み」と表示されている間は続きます。名前で保存したホストなら、そのたびにリゾルバーへの問い合わせも加わります。そして、あなたが設定したものは設定どおりに動きます。スケジュールしたバックアップは指定したミラーにコピーされ、Webhook はそれぞれのアドレスを呼び、スケジュールされたタスクやポート転送はそれぞれのホストに接続します — スケジュールされたタスクは実行ごとに 1 回接続し、スニペットが終わるとログアウトします。ですから、この主張は、当社自身がする価値があると言った唯一の形 — 確かめられる形 — で間違っていました。

共有したターミナルは、そのセッションが存在する二つめの場所であり、その二つめの場所はブラウザーのタブです。バイト列はあなたのマシンから相手のマシンへ渡り、ほかの何も通りません。どちらの側にも中継は置いていないので、バイト列を運ぶのはその 2 台のマシンだけです。これは選択です — TURN サーバーなら通信が見えてしまうので、Termiyo は使いません。そして当社のサーバーは、二人を引き合わせるだけです。使っているのは公開の STUN、Google と Cloudflare のもので、ホスト側が自分のアドレスが外からどう見えるかを尋ねるために使います。NAT の内側にいるホストは、それなしでは到達できないからです。この二つが知るのはそのアドレスだけで、ほかには何もありません。ゲストのブラウザーには STUN サーバーを一つも渡していません。ここからが代償です。ゲストはブラウザーで見ているので、拡張機能はそのページを読めますし、ブラウザーはタブのプレビューのためにその画面の画像を保持することがあります。ゲストは読み取り専用で始まり、あなたが許すまで入力できません。共有はあなたが止めたとき、または 4 時間後に終わります。そしてこれは、アプリ自身が与える保護と同じものではありません。ゲストのページは、ここだけでなくゲスト自身の画面でもそう伝えます。

当社が主張できないこと。SQLite ファイル自体は暗号化されていません。暗号化されているのは中のレコードです。そのファイルを持つ人には、ホストがいくつあるか、それぞれに最後に触れたのはいつか、どんな名前を付けたかが分かります。アドレス、ユーザー名、パスワード、鍵は暗号化されています。ご自身で気づかれるより、ここで申し上げるほうがよいと考えます。

何か見つけたら

セキュリティの報告は info@termiyo.com へ。2 営業日以内に受領を確認します。