すべてのページ
このページの内容

アクセストークンとリレーに接続できる範囲

リレーにはオーナーが 1 人、アクセストークンが 1 つあります。トークンを持つ人はリレーを完全に操作でき、そのエージェントを通じて、リレーを実行しているユーザーアカウントも操作できます。ユーザーアカウント、ロール、デバイスごとのキーはありません。このページでは、トークンがどこから来るか、ブラウザーやスクリプトがそれをどう提示するか、そもそも誰が接続できるか、トークンなしで何に到達できるか、漏れたときにどうするかを説明します。

トークン #

oar setup がトークンを作成し(新しい設定ファイルではランダムなもので、ランダムな英字、数字、-、_ からなる 43 文字)、設定ファイル(OAR の状態フォルダーにある config.json)の authToken に書き込みます。Windows 以外では、リレーはこのファイルを本人だけが読める状態に保ちます。config.json とシークレットの保存場所を参照してください。

設定ファイルに authToken がない場合、リレーは起動のたびにランダムなトークンを作り、ログに出力し、保存しません。--token <value> を付けてリレーを起動すると、そのトークンはその実行の間だけ使われます。保存されることはなく、コマンドラインの一部になります。エージェントは config.json からトークンを読み取るので(エージェントとトークンを参照)、エージェントを動かすなら、そこに保存されたトークンを使ってください。

oar url は、現在のトークン付きのアドレスを表示します(例:http://localhost:3333/?token=<your token>)。このアドレスはパスワードと同じように扱ってください。

提示する方法 #

方法 使う側
ページのアドレスの ?token= の部分 初回のブラウザー。ページはアドレスバーからトークンを取り除き、ヘッダーに入れてリレーに送ります。リレーは下記のサインイン用 Cookie で応答します。0.9.11 で追加 これが使えるのはページのアドレスだけです。API、ファイル、アセットのアドレスは ?token= を受け付けません
サインイン欄 Enter your access token to connect(接続するにはアクセストークンを入力してください)に入力して Connect(接続) Cookie を持たないブラウザー。誤ったトークンでは Invalid token(無効なトークン)、空欄では Please enter a token(トークンを入力してください)と表示されます
Authorization: Bearer <token> ヘッダー スクリプトと API 呼び出し
サインイン用 Cookie 以前にサインインしたブラウザー

トークンがリクエストの本文から読み取られることはなく、0.9.11 以降はリクエストのクエリからも読み取られません。リクエストにヘッダーと Cookie の両方がある場合、リレーはヘッダーを使います。誤った値は読み飛ばされません。Cookie が正しくても、ヘッダーが誤っていれば拒否されます。ライブ接続(Socket.IO)は、トークンを接続の auth.token フィールドか Cookie から読み取り、ヘッダーやクエリからは読み取りません。

アドレスに含まれるトークン

ページへの最初のリクエスト /?token=... は、アドレスにトークンを含んでいます。そのため、トークンがブラウザーの履歴、リレーの前に置いたリバースプロキシやトンネルのログ、アドレスをコピーした先に残ることがあります。ページは読み込み後にアドレスバーからトークンを取り除いてヘッダーでサインインし、それ以外のリクエストはアドレスからトークンを読み取りません。できる限り、サインイン欄かヘッダーを使ってください。

?token= を使っていたスクリプト

0.9.10 までは、リレーはすべてのリクエストで ?token= を受け付けていました。これを使って API、ファイル、アセットのアドレスを取得するスクリプトは、現在は 401 を受け取ります。代わりに Authorization: Bearer <token> を送ってください。Socket.IO クライアントはトークンを auth.token として渡します。アップグレードの注意点を参照してください。

有効なトークンを受け取ると、リレーは 30 日間有効な copilot_auth という名前の Cookie を設定します。ヘッダーでトークンを送るスクリプトに対しても同じです。この Cookie は HttpOnly なのでページのスクリプトからは読めず、SameSite=Lax です。リレーに HTTPS で接続した場合は Secure が付きます。トークンと一致しなくなった Cookie を持つリクエストが届くと、リレーは 401 を返して Cookie を消去し、ブラウザーにはサインイン欄が表示されます。Cookie にはトークンそのものが入っています。

サインアウトとデバイスの無効化 #

アプリにはリレーからサインアウトするボタンがなく、リレーはサインイン済みのデバイスの一覧を持ちません。Cookie にはトークンそのものが入っているので、1 台のデバイスだけを無効にすることはできません。自分のブラウザーでは、ブラウザーのサイト設定で Cookie を消去してください。紛失したものを含むすべてのデバイスを締め出すには、トークンを変更します(次のセクション)。

トークンのローテーション #

oar setup --new-token

これは新しいトークンを書き込み、リレーを再起動します(ターミナルでは先に確認します。oar setup を参照)。次のことが起きます。

  • サインイン済みのブラウザー。 リレーの再起動が終わると、古いトークンは使えなくなります。再起動でライブ接続が切れ、各ブラウザーの次のリクエストは失敗します。リレーはその Cookie を消去し、ブラウザーにはサインイン欄が表示されます。oar url のアドレスか新しいトークンで、もう一度サインインしてください。
  • 再起動まで。 再起動を断った場合、実行中のリレーは oar restart まで古いトークンを受け付け続けます。
  • ペアリングしたリレー。 ペアリングしたことでこちらのトークンを保存しているリレーには、Token not accepted(トークンが受け付けられません)と表示されます。そちらで新しいトークンを使ってリレーをもう一度追加してください。リモートリレーを参照してください。このリレーでペアリングを削除しても、相手側がすでに持っているトークンは無効になりません。そのリレーを締め出すには、トークンをローテーションします。
  • relay-previous.json。 変更したポートやトークンが再起動を待っている間、oar setup は古いポートとトークンをデータフォルダーにあるこのファイルに保存します(平文で、本人だけが読めます)。これにより、oar status、oar stop、oar restart は実行中のリレーを見つけられます。これは猶予期間ではありません。このファイルはリレーが何を受け付けるかを一切変えず、リレーが新しい設定で応答すると oar コマンドがファイルを削除します。古いトークンが使えなくなるのは、リレーが再起動したときだけです。
  • 共有リンクとプレビューリンクは独自のトークンを持つので、影響を受けません。

ファイルの authToken を手で編集しても同じように機能します。oar restart で反映されます。

そもそも誰が接続できるか #

リレーがどこで待ち受けるかは、設定ファイルの localhostOnly で決まります。

localhostOnly セットアップのオプション リレーが待ち受けるアドレス 接続できる範囲
true(既定) oar setup --local、または 1 と答える 127.0.0.1 このマシンのみ
それ以外の値 oar setup --lan、または 2 と答える 0.0.0.0(すべてのインターフェース) マシンのアドレスとポートに到達できるすべてのデバイス

ローカルとみなされるのは、真偽値の true と文字列の "true"(大文字・小文字を問わない)だけです。false、null、1、"yes" などそれ以外の値はすべて、リレーをネットワークに開きます。既定値が使われるのは、キーがないときだけです。oar setup はキーを true か false として書き込みます。変更には oar restart が必要です。

oar setup、oar url、oar status は、このキーを別の方法で読み取ります。これらにとって LAN アクセスとみなされるのは真偽値の false だけで、oar doctor が localhostOnly: no と表示するのも false のときだけです。null や "no" のような値では、リレーはすべてのインターフェースで待ち受ける一方、これらのコマンドは this machine only(このマシンのみ)と報告します。キーは true か false にしておいてください。config.json を参照してください。

LAN では、トークンが唯一の関門です。リレーはリクエストがどこから来たかを確認しません。アクセスが this machine only の場合、LAN アクセスを有効にするかトンネルを使うまで、スマートフォンからは接続できません。localhostOnly は、マシンから外向きに接続する管理対象のトンネルには影響しません。

同じマシン上のプロキシやトンネルの背後にあるリレーは、this machine only のままにできます。リレーがどのプロキシの X-Forwarded-* ヘッダーを信頼するかは trustProxy(既定は loopback)で決まり、それによって接続を HTTPS とみなして Cookie に Secure を付けるかどうかが決まります。

トークンが必要なもの #

会話、ファイル、設定、エージェントを読み取ったり変更したりするものは、すべてトークンが必要です。例外は次のとおりで、これがすべてです。

パス トークンが必要か 得られるもの
/ と /index.html 不要 Web アプリとそのサインイン欄
Web アプリのスクリプト、スタイル、アイコンのファイル、/sw.js、/socket.io/socket.io.js 不要 アプリ本体。データは一切含みません
/manifest.webmanifest 不要 インストール用のマニフェスト。Settings(設定)で設定したアプリ名を含みます
/shared/<link token> 不要 共有された会話のページ
/api/shared/<link token> と、その presence、アップロード、生成画像のルート 不要。ただし有効で取り消されていないリンクトークンが必要 その 1 つの会話への読み取り専用アクセス。共有を参照
プレビューホスト上のプレビューリンク 不要。ただし有効なプレビュートークンが必要 プレビューしているアプリだけ。プレビューホストはリレーを提供しません。プレビューを参照
/api/...(その他のすべてのルート) 必要 会話、設定、ファイル、ステータス、プレビュー、ペアリング
ライブ接続(Socket.IO) 必要。さらに 0.9.11 で追加 ブラウザーはリレー自身のアドレスから接続を開く必要があります アプリのライブ更新。ホストを書き換えるプロキシについては allowedOrigins を参照
ワーカーからリレーへの接続 必要 このマシン上のエージェント自身のプロセスが使います
ドライブやワークスペースのファイル、アップロード、生成画像(それぞれ自身のアドレスで) 必要 共有の閲覧者はこの方法では読み込めません。その会話が使うものは、上の共有用ルートが提供します。メディアとファイルを参照

認証なしのヘルスチェックやバージョンのエンドポイントはありません。oar status が呼び出す /api/status もトークンが必要です。

共有リンクとプレビューリンクは、設計上公開されています。リンクのランダムなトークンが唯一の保護なので、使い終わったら閉じるか取り消してください。リレーが提供するファイルにはサンドボックスのポリシーが付くので、提供された HTML や SVG のファイルがリレーのオリジンでスクリプトを実行することはできません。

ワーカーの接続は、プロキシやトンネルが転送していない、リレー自身のマシンからのリクエストにだけ応答します。それ以外は、トークンを確認する前に 403 で拒否されます。トンネル経由の共有リンクは影響を受けません。セッションワーカーのパスガードを参照してください。

サインインの保護 #

  • サインインとライブ接続では、リレーは定数時間でトークンを比較します。
  • 0.9.11 で追加 誤ったトークンが 10 回で、そのアドレスは 1 分間ロックアウトされます。 1 つのクライアントアドレスから 1 分以内に誤ったトークンが 10 回届くと(ヘッダー、Cookie、サインイン欄、ライブ接続のハンドシェイクのいずれでも)、その 1 分が終わるまで、リレーはそのアドレスに Retry-After 付きの 429 を返します。正しいトークンでも同じです。サインイン欄には Too many failed sign-in attempts. Try again in 42 seconds.(サインインの失敗が多すぎます。42 秒後にもう一度お試しください。)と表示されます。同じ誤った値の繰り返しは 1 回と数えるので、古い Cookie を持つタブのせいで締め出されることはありません。アドレスを拒否すると、リレーは [auth] で始まる行をログに出します。
  • プロキシやトンネルが転送していない、リレー自身のマシンからのリクエストは、数えられることもロックアウトされることもありません。そのため、リレーのワーカーやエージェントのツールは動作し続けます。
  • クライアントアドレスは、リレーが信頼するアドレスです。リレーが信頼していない別のマシン上のプロキシの背後では、すべてのクライアントがプロキシのアドレスになり、1 つのクライアントの誤ったトークンで全員がロックアウトされます。
  • ロックアウトは推測を遅らせるだけで、良いトークンの代わりにはなりません。トークンは長くランダムにしておいてください。oar setup が生成するので、短い単語に置き換えないでください。
  • トークンが不要なルートでの唯一のレート制限は、共有された会話の presence ping に対するもので、共有リンクとクライアントアドレスごとに 10 秒あたり 24 回です。0.9.11 で追加 クライアントアドレスはロックアウトと同様に trustProxy に従うので、クライアントが X-Forwarded-For を送って自分のアドレスを選ぶことはできません。
  • トークンはログに書き込まれません。例外は、設定ファイルにトークンがなく、リレーが起動時に一時的なトークンを作る場合です。oar start と oar url は、トークンをターミナルに表示します。

エージェントとトークン #

エージェントは、リレーを実行しているユーザーのプロセスとして、リレーのマシン上で動きます。エージェントは独自の認証情報を持ちません。リレーと通信するときは、config.json からリレー自身のトークンを読み取り、オーナーと同じように送ります。リレーはエージェントの環境変数やプロンプトにトークンを入れませんが、エージェントは同じ OS ユーザーとして動くので、ファイルを読み、トークンも読めます。エージェントが実行するものも同じです。トークンは実行するすべてのエージェントに知られているものとして扱い、リレーを任せられると信頼するユーザーとしてのみエージェントを実行してください。

リレーは、ペアリングしたリレーのトークンをエージェントに教えません。エージェントはこのリレーを通じてペアリングしたリレーに接続し、このリレーが保存済みのトークンを付け加えます(リモートリレー)。また、エージェントはリレーを実行しているユーザーの権限で動くので、リレーのオーナーがマシン上でできることは何でも、エージェントに頼んで実行させられます。

LAN 上の平文 HTTP #

LAN アクセスで http:// のアドレスを使う場合、トークンと Cookie は暗号化されずにネットワークを流れます。その通信を見られる人は誰でもトークンを読めます。信頼できるネットワークで使うか、前段に HTTPS を置いてください。平文の HTTP では、Cookie に Secure は付きません。

OAR のアプリとしてのインストールとプッシュ通知には HTTPS か localhost が必要なので、平文の LAN アドレスではどちらも使えません。アプリとしてインストールと通知を参照してください。

トークンが漏れたと思ったら #

  1. oar setup --new-token を実行し、リレーを再起動させます。すべてのブラウザーがサインアウトされます。再起動を断った場合は oar restart を実行してください。それまでは古いトークンが使えたままです。
  2. oar url のアドレスで、もう一度サインインします。
  3. このリレーとペアリングしたすべてのリレーで、新しいトークンを使ってこのリレーをもう一度追加します(リモートリレー)。
  4. トークンが保存された場所を確認します。スクリプト、シェルの履歴、チャットに貼り付けたアドレス、config.json のコピーやバックアップです。
  5. Settings → Sharing(設定 → 共有)で共有リンクを停止または更新し(共有中のリンク)、心当たりのないプレビューを閉じます。これらは独自のトークンを持っています。
  6. リレーが露出している間に誰かが使えた可能性があるなら、そのエージェントが何をしたかを確認します。トークンを持つ人は、リレーのユーザーとしてコマンドを実行するエージェントを起動できます。