所有頁面
本頁內容

存取 token 與誰能連到中繼

一個中繼只有一位擁有者和一個存取 token。持有 token 的人就能完全控制中繼,並透過它的 agent 控制中繼執行時所用的使用者帳戶。這裡沒有使用者帳戶、角色,也沒有每台裝置各自的金鑰。本頁說明 token 從哪裡來、瀏覽器或腳本如何出示它、到底誰能連線、哪些內容不需要它就能存取,以及 token 外洩時該怎麼做。

Token #

oar setup 會建立 token(新設定檔會得到一個隨機 token,由 43 個隨機的字母、數字、- 和 _ 組成),並把它寫入設定檔中的 authToken,也就是 OAR 狀態資料夾中的 config.json。在 Windows 以外的系統上,中繼會讓這個檔案只有你能讀取。見 config.json 和機密存放在哪裡。

設定檔中沒有 authToken 時,中繼每次啟動都會產生一個隨機 token,印在它的記錄中,而且不會儲存。用 --token <value> 啟動中繼時,該 token 只用於這次執行;它永遠不會被儲存,而且會出現在指令列中。你的 agent 是從 config.json 讀取 token(見 Agent 與 token),所以如果要讓 agent 運作,請使用儲存在那裡的 token。

oar url 會印出帶有目前 token 的位址,例如 http://localhost:3333/?token=<your token>。請把這個位址當成密碼看待。

出示 token 的方式 #

方式 適用對象
頁面位址中的 ?token= 部分 瀏覽器,第一次時。頁面會把 token 從網址列取出,放在標頭中送給中繼;中繼會以下方說明的登入 cookie 回應。0.9.11 新增 它只對頁面位址有效:API、檔案和資源位址不接受 ?token=
登入框 Enter your access token to connect(輸入你的存取 token 以連線),然後按 Connect(連線) 沒有 cookie 的瀏覽器。token 錯誤時會顯示 Invalid token(token 無效);登入框空白時會顯示 Please enter a token(請輸入 token)
Authorization: Bearer <token> 標頭 腳本和 API 呼叫
登入 cookie 先前登入過的瀏覽器

中繼絕不會從請求本文讀取 token,自 0.9.11 起也不會從請求的查詢字串讀取。如果請求同時帶有標頭和 cookie,中繼會使用標頭。錯誤的值不會被略過:即使 cookie 正確,錯誤的標頭也會被拒絕。即時連線(Socket.IO)會從連線的 auth.token 欄位或 cookie 讀取 token,不會從標頭讀取,也不會從它的查詢字串讀取。

位址中的 token

對頁面的第一個請求 /?token=... 會在位址中帶著 token。所以 token 可能會留在瀏覽器的歷史記錄中、中繼前方反向 proxy 或 tunnel 的記錄中,以及你把這個位址複製進去的任何地方。頁面載入後會把它從網址列移除,並以標頭登入,而且沒有其他請求會從位址取得 token。能用登入框或標頭時,請優先使用。

使用 ?token= 的腳本

到 0.9.10 為止,中繼在每個請求上都接受 ?token=。用它擷取 API、檔案或資源位址的腳本,現在會得到 401:請改為傳送 Authorization: Bearer <token>。Socket.IO 用戶端則以 auth.token 傳遞 token。見升級說明。

收到有效的 token 後,中繼會設定一個名為 copilot_auth 的 cookie,有效期 30 天。在標頭中傳送 token 的腳本也一樣會收到。它是 HttpOnly,所以頁面腳本無法讀取它,而且是 SameSite=Lax。透過 HTTPS 連到中繼時,它會標上 Secure。如果請求帶著已不再符合 token 的 cookie,中繼會回應 401 並清除該 cookie,瀏覽器則會顯示登入框。cookie 中存放的就是 token 本身。

登出與撤銷裝置 #

App 中沒有登出中繼的按鈕,中繼也不會保留已登入裝置的清單。因為 cookie 中存放的就是 token 本身,所以無法單獨撤銷某一台裝置。在你自己的瀏覽器上,請在瀏覽器的網站設定中清除 cookie。要把所有裝置(包括你遺失的那台)都擋在外面,請更換 token(下一節)。

更換 token #

oar setup --new-token

這會寫入新的 token 並重新啟動中繼(在終端機中會先詢問;見 oar setup)。會發生的事:

  • 已登入的瀏覽器。 中繼重新啟動後,舊 token 就會失效。重新啟動會中斷即時連線,每個瀏覽器的下一個請求都會失敗:中繼會清除它的 cookie,瀏覽器則顯示登入框。請用 oar url 提供的位址或新的 token 重新登入。
  • 重新啟動之前。 如果你拒絕重新啟動,執行中的中繼會繼續接受舊 token,直到執行 oar restart 為止。
  • 配對的中繼。 因為你們配對過而存有你的 token 的中繼,會收到 Token not accepted(Token 未被接受)。請在那邊用新的 token 重新新增此中繼;見遠端中繼。在這個中繼上移除配對,並不會撤銷另一端已經持有的 token,所以更換 token 才是把那個中繼擋在外面的方法。
  • relay-previous.json。 當變更後的連接埠或 token 還在等待重新啟動時,oar setup 會把舊的連接埠和 token 保存在資料目錄的這個檔案中(純文字,只有你能讀取),讓 oar status、oar stop 和 oar restart 仍能找到執行中的中繼。這不是寬限期:這個檔案完全不會改變中繼接受什麼,而且一旦中繼以新的設定回應,oar 指令就會刪除它。舊 token 只有在中繼重新啟動時才會失效。
  • 分享連結和預覽連結 有自己的 token,不受影響。

手動編輯檔案中的 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" 和其他任何值,都會讓中繼對網路開放;只有在缺少這個 key 時才會套用預設值。oar setup 會把這個 key 寫成 true 或 false。變更後需要執行 oar restart。

oar setup、oar url 和 oar status 解讀這個 key 的方式不同:對它們來說,只有布林值 false 才算區域網路存取,而 oar doctor 只在值為 false 時才顯示 localhostOnly: no。如果值是 null 或 "no" 之類,中繼會在所有介面上監聽,這些指令卻回報 this machine only(僅限本機)。請讓這個 key 保持為 true 或 false。見 config.json。

在區域網路上,token 是唯一的關卡:中繼不會檢查請求來自哪裡。存取設為 this machine only 時,手機無法連線,除非你開啟區域網路存取,或使用 tunnel。localhostOnly 不會影響受管理的 tunnel,因為它們是從這台機器向外連線。

位於同一台機器上的 proxy 或 tunnel 後面的中繼,可以維持 this machine only。中繼相信哪些 proxy 的 X-Forwarded-* 標頭,由 trustProxy(預設 loopback)決定;這會決定它是否把連線視為 HTTPS,並把 cookie 標上 Secure。

哪些需要 token #

凡是讀取或變更你的對話、檔案、設定或 agent 的東西,都需要 token。以下是例外,而且就是完整的清單。

路徑 需要 token 嗎? 提供什麼
/ 和 /index.html 否 網頁 App 和它的登入框
網頁 App 的腳本、樣式和圖示檔、/sw.js、/socket.io/socket.io.js 否 App 本身,其中不含你的任何資料
/manifest.webmanifest 否 安裝資訊清單。它帶有你在 Settings(設定)中設定的 App 名稱
/shared/<link token> 否 分享的對話的頁面
/api/shared/<link token> 及其線上狀態、上傳和生成圖片的路由 否,但需要有效且未撤銷的連結 token 對那一個對話的唯讀存取。見分享
預覽主機上的預覽連結 否,但需要有效的預覽 token 只有被預覽的 App;預覽主機不提供中繼。見預覽
/api/...(其他所有路由) 是 對話、設定、檔案、狀態、預覽、配對
即時連線(Socket.IO) 是,而且 0.9.11 新增 瀏覽器必須從中繼自己的位址開啟它 App 的即時更新。proxy 會改寫主機時,見 allowedOrigins
worker 與中繼之間的連線 是 由這台機器上你的 agent 自己的處理程序使用
透過各自位址存取的磁碟機和 workspace 中的檔案、上傳的檔案和生成的圖片 是 分享的觀看者無法用這種方式載入它們;上面的分享路由會提供該對話用到的那些。見媒體與檔案

沒有不需驗證的健康檢查或版本端點:oar status 呼叫的 /api/status 需要 token。

分享連結和預覽連結在設計上就是公開的。連結中的隨機 token 是它唯一的保護,所以用完後請關閉或撤銷它們。中繼提供的檔案會附帶沙箱政策送出,所以被提供的 HTML 或 SVG 檔案無法在中繼的來源上執行腳本。

worker 的連線只回應來自中繼本機、且沒有經過任何 proxy 或 tunnel 轉送的請求;其他請求會在檢查 token 之前就以 403 拒絕。透過 tunnel 的分享連結不受影響。見 session worker 路徑保護。

登入的防護 #

  • 在登入和即時連線上,中繼以固定時間比較 token。
  • 0.9.11 新增 錯誤的 token 達十次,就會把一個位址鎖住一分鐘。 一分鐘內來自同一個用戶端位址的十個錯誤 token(不論是在標頭、cookie、登入框或即時連線的交握中),會讓中繼對該位址回應 429 並附上 Retry-After,直到這一分鐘結束,即使是正確的 token 也一樣。登入框會顯示 Too many failed sign-in attempts. Try again in 42 seconds.(登入失敗次數過多。請在 42 秒後重試。)重複送出同一個錯誤值只算一次,所以帶著舊 cookie 的分頁不會把你鎖在外面。中繼拒絕某個位址時,會記錄一行以 [auth] 開頭的記錄。
  • 來自中繼本機、且沒有經過任何 proxy 或 tunnel 轉送的請求,永遠不會被計數,也永遠不會被鎖住,所以中繼的 worker 和 agent 的工具能持續運作。
  • 用戶端位址是中繼信任的那個位址。在中繼不信任的另一台機器上的 proxy 後面,每個用戶端的位址都是 proxy 的位址,一個用戶端的錯誤 token 就會把所有用戶端都鎖住。
  • 鎖定能減慢猜測,但無法取代好的 token。請讓 token 保持夠長且隨機:oar setup 會產生一個;不要把它換成短短的單字。
  • 不需要 token 的路由上唯一的速率限制,是分享對話的線上狀態 ping:每個分享連結和用戶端位址每 10 秒 24 次。0.9.11 新增 用戶端位址和鎖定一樣依循 trustProxy,所以用戶端無法藉由傳送 X-Forwarded-For 自己挑選位址。
  • token 不會寫入記錄,除非設定檔中沒有 token,中繼在啟動時產生了一個臨時 token。oar start 和 oar url 會把它印到你的終端機上。

Agent 與 token #

你的 agent 以中繼執行時所用使用者的處理程序,在中繼的機器上執行。它們沒有自己的憑證:要和中繼溝通時,它們會從 config.json 讀取中繼自己的 token,並像擁有者一樣送出。中繼不會把 token 放進 agent 的環境或提示中,但 agent 以同一個作業系統使用者的身分執行,所以它能讀取那個檔案,連同其中的 token。agent 執行的任何東西也一樣。請把 token 視為你執行的每個 agent 都知道,並且只以你放心把中繼交給他的使用者身分執行 agent。

中繼不會把配對的中繼的 token 告訴 agent:agent 是透過這個中繼連到配對的中繼,由這個中繼加上儲存的 token(遠端中繼)。agent 也以中繼執行時所用使用者的權限行事,所以中繼擁有者在這台機器上能做的任何事,都可以要求 agent 去做。

區域網路上的純 HTTP #

啟用區域網路存取並使用 http:// 位址時,token 和 cookie 會以未加密的方式經過網路。任何能監看這些流量的人都能讀到 token。請只在你信任的網路上使用,或在前面加上 HTTPS。在純 HTTP 上,cookie 不會標上 Secure。

把 OAR 安裝成 App 和推播通知都需要 HTTPS 或 localhost,所以在純區域網路位址上兩者都無法運作:見安裝成 App 和推播通知。

如果你認為 token 外洩了 #

  1. 執行 oar setup --new-token,並讓它重新啟動中繼。每個瀏覽器都會被登出。如果你拒絕重新啟動,請執行 oar restart:在那之前,舊 token 仍然有效。
  2. 用 oar url 提供的位址重新登入。
  3. 在每個與這個中繼配對過的中繼上,用新的 token 重新新增這個中繼(遠端中繼)。
  4. 檢查 token 曾被存放在哪裡:腳本、shell 歷史記錄、你貼到聊天訊息中的位址,以及 config.json 的副本或備份。
  5. 在 Settings → Sharing(設定 → 分享)中停止或更新分享連結(你的分享連結),並關閉你不認得的預覽。它們有自己的 token。
  6. 如果中繼暴露期間可能有人使用過它,請查看它的 agent 做了什麼。token 持有者可以啟動 agent,以中繼的使用者身分執行指令。