所有页面
本页内容

访问令牌与谁能访问中继

一个中继有一个所有者和一个访问令牌。持有令牌的人拥有对中继的完全控制权,并通过其智能体拥有对中继所运行的那个用户账户的控制权。没有用户账户、角色或按设备区分的密钥。本页说明令牌从何而来、浏览器或脚本如何出示它、谁能连接、没有令牌时哪些内容可访问,以及它泄露时该怎么办。

令牌 #

oar setup 创建令牌(新配置文件会生成一个随机的:43 个字符,由随机字母、数字、- 和 _ 组成),并把它写入配置文件的 authToken 键——即 OAR 状态文件夹中的 config.json。除 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 传递。参见升级说明。

收到有效令牌后,中继会设置一个名为 copilot_auth 的 cookie,有效期 30 天。对于在请求头中发送令牌的脚本,这同样会发生。它是 HttpOnly,因此页面脚本无法读取它,并且 SameSite=Lax。当通过 HTTPS 访问中继时,它会被标记为 Secure。如果请求携带的 cookie 不再与令牌匹配,中继会回应 401 并清除该 cookie,浏览器会显示登录框。cookie 本身就保存着令牌。

退出登录与撤销设备 #

应用没有针对中继的退出登录按钮,中继也不保存已登录设备的列表。因为 cookie 本身保存着令牌,所以无法单独撤销某台设备。在你自己的浏览器上,在浏览器的站点设置中清除该 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 读取该键的方式不同:对它们而言只有布尔值 false 算作局域网访问,而 oar doctor 只在 false 时显示 localhostOnly: no。当值为 null 或 "no" 等时,中继监听所有网络接口,而这些命令报告 this machine only(仅本机)。请把该键保持在 true 或 false。参见 config.json。

在局域网中,令牌是唯一的关卡:中继不检查请求来自哪里。在 this machine only 访问下,手机无法连接,直到你开启局域网访问或使用隧道。localhostOnly 不影响托管隧道,它们从本机向外连接。

位于同一台机器上的代理或隧道后面的中继可以保持 this machine only。中继相信哪些代理的 X-Forwarded-* 请求头由 trustProxy 决定(默认 loopback);它决定中继是否把连接视为 HTTPS 并把 cookie 标记为 Secure。

什么需要令牌 #

凡是读取或更改你的对话、文件、设置或智能体的操作都需要令牌。以下是例外情况,也是完整的清单。

路径 需要令牌吗? 它提供什么
/ 和 /index.html 否 网页应用及其登录框
网页应用的脚本、样式和图标文件,/sw.js、/socket.io/socket.io.js 否 应用本身,它不保存你的任何数据
/manifest.webmanifest 否 安装清单。它携带你在 Settings(设置)中设置的应用名称
/shared/<link token> 否 已分享的对话的页面
/api/shared/<link token> 及其在线状态、上传和生成图片路由 否,但需要有效且未被撤销的链接令牌 对该单个对话的只读访问。参见分享
预览主机上的预览链接 否,但需要有效的预览令牌 仅被预览的应用;预览主机不提供中继服务。参见预览
/api/...(所有其他路由) 是 对话、设置、文件、状态、预览、配对
实时连接(Socket.IO) 是,并且 0.9.11 新增 浏览器必须从中继自己的地址打开它 应用的实时更新。对于重写主机的代理,参见 allowedOrigins
worker 与中继的连接 是 由你本机上智能体自己的进程使用
你的驱动器和工作区中的文件、上传文件和生成图片(按它们自己的地址) 是 分享查看者无法这样加载它们;上面的分享路由提供该对话所用的那些。参见媒体与文件

没有不需要认证的健康检查或版本端点:oar status 调用的 /api/status 需要令牌。

分享链接和预览链接在设计上就是公开的。链接的随机令牌是它唯一的保护,因此用完后就关闭或撤销它们。中继提供的文件会附带沙箱策略发送,因此被提供的 HTML 或 SVG 文件无法在中继的源上运行脚本。

worker 的连接只回应来自中继自己机器的、未经任何代理或隧道转发的请求;其他任何请求都会在检查令牌之前被以 403 拒绝。通过隧道的分享链接不受影响。参见会话 worker 的路径保护。

登录保护 #

  • 对于登录和实时连接,中继以恒定时间比较令牌。
  • 0.9.11 新增 十个错误令牌会让一个地址被锁定一分钟。 一个客户端地址在一分钟内从请求头、cookie、登录框或实时连接握手中发出十个错误令牌,会让中继在该分钟结束前一直对该地址回应 429 并附带 Retry-After,正确的令牌也不例外。登录框显示 Too many failed sign-in attempts. Try again in 42 seconds.(登录失败次数过多。请在 42 秒后重试。)同一个重复的错误值只计一次,因此带旧 cookie 的标签页不会把你锁在外面。当中继拒绝某个地址时,会记录一行以 [auth] 开头的日志。
  • 来自中继自己机器、未经任何代理或隧道转发的请求绝不会被计数,也绝不会被锁定,因此中继的 worker 和智能体的工具会继续工作。
  • 客户端地址是中继信任的那个。在另一台机器上的、中继不信任的代理后面,每个客户端都具有代理的地址,一个客户端的错误令牌会把所有客户端都锁在外面。
  • 锁定会减缓猜测;它不能替代一个好的令牌。请保持令牌足够长且随机:oar setup 会生成一个;不要把它换成一个短词。
  • 对不需要令牌的路由的唯一速率限制是分享对话在线状态的心跳:每个分享链接和客户端地址每 10 秒最多 24 次。0.9.11 新增 客户端地址与锁定一样遵循 trustProxy,因此客户端无法通过发送 X-Forwarded-For 来挑选自己的地址。
  • 令牌不会写入日志,除非配置里没有令牌、中继在启动时生成一个临时令牌。oar start 和 oar url 会把它打印到你的终端。

智能体与令牌 #

你的智能体作为中继所运行的那个用户的进程,在中继的机器上运行。它们没有自己的凭据:为了与中继通信,它们从 config.json 读取中继自己的令牌,并像所有者那样发送。中继不会把令牌放入智能体的环境或提示词中,但智能体以相同的操作系统用户身份运行,因此它可以读取该文件和其中的令牌。智能体运行的任何东西也是如此。请把令牌视为你运行的每个智能体都知道的,并且只用你放心交出中继控制权的用户身份来运行智能体。

中继不会把已配对中继的令牌告诉智能体:智能体通过本中继访问已配对的中继,本中继会加上保存的令牌(远程中继)。智能体还以中继所运行用户的权限行事,因此中继所有者在机器上能做的任何事,都可以要求智能体去做。

局域网上的明文 HTTP #

在局域网访问和 http:// 地址下,令牌和 cookie 会以未加密的方式穿过网络。任何能观察到该流量的人都能读到令牌。请在你信任的网络上使用它,或者在前面加一层 HTTPS。在明文 HTTP 上,cookie 不会被标记为 Secure。

将 OAR 安装为应用和推送通知需要 HTTPS 或 localhost,因此两者在明文局域网地址上都无法工作:参见安装为应用和通知。

如果你认为令牌已泄露 #

  1. 运行 oar setup --new-token 并让它重启中继。每台浏览器都会被退出登录。如果你拒绝重启,请运行 oar restart:在那之前旧令牌仍然有效。
  2. 用 oar url 的地址重新登录。
  3. 在你与这个中继配对过的每个中继上,用新令牌重新添加这个中继(远程中继)。
  4. 检查令牌曾存放在哪里:脚本、shell 历史记录、你粘贴到对话中的地址,以及 config.json 的副本或备份。
  5. 在 Settings → Sharing(设置 → 分享)中停止或更新分享链接(你的分享链接),并关闭你不认识的预览。它们有自己的令牌。
  6. 如果中继暴露期间可能有人使用过它,请查看它的智能体做了什么。令牌持有者可以启动以中继用户身份运行命令的智能体。