Remote Web Access / Owner only / Self-hosted

四种访问方式,一套所有者认证

同机、局域网或 VPN、SSH 隧道、所有者域名与 HTTPS 反向代理全部支持。 每次 Web 启动生成实例 token;HTTP、SSE、WebSocket 使用同一认证规则; OpenProgram 不运营公网中转,不增加账号、RBAC 或项目权限。

HOST解析 authority
CLASSIFYroute / method / source
ORIGIN浏览器与 CSRF
TOKENcookie 或 Bearer
AUTHORITY映射 owner tier
ACTIONHTTP / SSE / WS
01

方法与产品边界

Web UI 是一个完整的所有者管理权限边界。多人协作继续使用 channel speaker 归因与受限 capability,不转化为 Web 账号。

Same machine

同机访问

127.0.0.1

CLI 自动打开带 fragment token 的 loopback URL。

token 始终开启;Host 与 Origin 仍校验。
LAN / VPN

直接网络访问

web.host = 0.0.0.0

必须显式配置完整、精确的 allowed_origins

HTTP 仅限显式本地/overlay 地址范围并警告;其他情况使用 HTTPS。
SSH tunnel

SSH 端口转发

127.0.0.1

浏览器连接本地转发端口,SSH 提供传输加密。

不修改 web.host,实例 token 继续认证。
Public domain

HTTPS 反向代理

proxy → 127.0.0.1

nginx 或 Caddy 在同机终结 HTTPS,保留公网 Host。

只信任 loopback proxy;OpenProgram 不管理证书。
FOUR SUPPORTED DEPLOYMENTS · ONE APPLICATION CREDENTIAL LOCAL Browser Open- Program 127.0.0.1 TOKEN + HOST + ORIGIN 本机也不豁免认证 LAN / VPN Device Open- Program EXPLICIT web.host NONEMPTY EXACT ORIGINS 缺少配置时拒绝启动 SSH TUNNEL Browser SSH Open- Program BACKEND LOOPBACK SSH ENCRYPTION + TOKEN 不修改 web.host PUBLIC HTTPS Browser nginx / Caddy Open- Program HTTPS → LOOPBACK OWNER DOMAIN + TOKEN 无 OpenProgram relay
本机直接网络 SSH公网 HTTPS
边界:不做 Web 账号、RBAC、项目权限、OAuth/SSO、内置 TLS、证书生命周期、公网中转、托管隧道、公共分享 URL 或关闭认证模式。
02

当前实现与待补控制

Owner process token、canonical Origin、fragment bootstrap、共同 HTTP/WS 认证边界、auth-url 和最小 health 已进入生产路径;secret 不可取回与完整部署验收仍未完成。

Current behavior

OwnerAuthMiddleware 先认证

OwnerAuthState 生成 32 字节 token、持有 per-state lock、写 owner-only token file 与不含 token 的 access.json,并派生 profile-specific cookie。OwnerAuthMiddleware 在 route dispatch 前验证 Host/request origin 与 cookie 或 Bearer。

认证成功后才附加当前 profile 的 owner authority;WebSocket 校验发生在 accept() 前。Uvicorn 使用 proxy_headers=False

Remaining work

收敛 secret 与验收范围

两条 plaintext reveal 路径和 frontend control 仍需删除,并实现独立的 config-key 与 account replace/preserve/delete schema。

还缺少直接 HTTP startup warning、独立 SSE、真实 browser bootstrap/WS、restart、bind-failure、multi-profile 与 nginx/Caddy smoke 验收。

当前实现与缺失控制
当前对象已实现缺失或风险
OwnerAuthStatetoken、lock、owner-only files、access snapshot、cookie、常数时间比较真实 bind-failure、restart 与 multi-profile 验收缺失
Canonical Origineffective Origin、非 loopback fail-closed、本地 HTTP 网段startup 输出尚缺完整字段与直接 HTTP 警告
OwnerAuthMiddlewareHTTP/WS、cookie/Bearer、Host/Origin/CSRF、owner authority缺少独立 SSE 与真实 browser WS 验收
Fragment bootstrapbackend、frontend gate、同步清除、无 Web Storage、auth-url缺少 browser-level end-to-end 验收
Reverse proxyproxy_headers=False 与 loopback-only forwarded schemenginx/Caddy HTTPS、WS、SSE smoke 未测试
Provider secret部分响应默认掩码两个 reveal 路径返回明文
/healthz只返回 status=ok;详细字段位于受保护的 /api/diagnostics完整 response-class cache audit 尚未完成
Loopback 不是认证。任意网页可以向 localhost 发送请求;WebSocket 不受 HTTP 同源读取规则保护;本机进程可以省略 Origin;DNS rebinding 可以提供外部 Host。因此 token 在本机也强制开启。
03

开源实现调查

范围包括现有参考语料与具备远程 Web、认证、反向代理或 secret 处理能力的补充系统;目标能力不存在时明确标为不适用。

开源框架远程访问设计对比
系统默认与认证远程方式采用拒绝或不适用
OpenClawloopback;外部需要认证;显式 OriginSSH、反向代理、其他外部网络方式fragment、Host/Origin、proxy trusttokenless identity 替代
Jupyter ServerNotebook 4.3 默认 token;首次访问转 cookieSSH、HTTPS public server自动 token → cookie 体验query token、密码模式
Hermes Agentloopback;外部 bind 强制 auth provider 并 fail closedsession cookie;单次 WS ticket外部 fail-closed、secret redactionauth-provider 账号、第二套 ticket、reveal
Agent Zero本地;可选单组登录;cookie + CSRF反向代理、VPS、内置 tunnelcookie/CSRF/Origin/WS、secret mask可关闭认证、内置公网 tunnel
OpenHandssession API key;HTTP/WSSSH、nginx/HTTPS实例 key、loopback backend公共 HTML/browser storage 暴露 token、明文 secret retrieval
opencodeloopback;未设置密码时无认证外部 host、CORS origins;另有 WS ticketloopback default可选认证、第二套 WS ticket
Open WebUI账号、角色、JWT/cookienginx/Caddy、WS、SSEproxy、Upgrade、SSE buffering 配置账号、group、RBAC
Difyaccount/workspace/role反向代理credential obfuscation 与替换语义tenant 与 role 层
LibreChat注册、JWT、角色与 ACLnginx HTTPS/WSproxy 细节用户身份数据模型
AnythingLLM单用户或多用户;单用户密码可选Docker port单一 owner credential 概念可选认证、role system
AutoGen Studioloopback;默认无认证;可选 OAuth/JWTresearch prototypeloopback defaultquery/localStorage token、post-accept auth
SWE-agent当前仓库提供命令行 agent无 owner Web control UI记录能力缺失远程安全设计不适用
pi-mono / pi-aiTUI、SDK、RPC/provider transport无 packaged owner Web server记录能力缺失远程 Web ownership 不适用
WeClawWeChat gateway + HTTP APIlisten address 可配记录外部 HTTP 与 Web UI 的区别浏览器 owner UI 不存在
Codex CLIapp-server 与实验性 WSservice-mediated pairing/remote control记录协议差异不采用 relay 型 remote control
三类远程身份设计
类型框架或能力OpenProgram 处理
实例 credentialJupyter、OpenClaw、OpenHands采用:一个 owner,一个根密钥,两种传输凭证形式
应用账号Open WebUI、Dify、LibreChat、AnythingLLM不采用:不需要注册、role、resource ACL
托管远程控制pairing、hosted tunnel、relay service不采用:OpenProgram 不运营外部服务
04

采用、修改与拒绝

最终设计只保留完成当前需求所需的一个根密钥(实例 token)、两种传输凭证形式(Bearer header 与 profile 作用域 HttpOnly cookie)、一套浏览器 bootstrap 和一组 HTTP/WS/SSE 认证规则。

采用
OpenClaw 的精确 Origin、Host/DNS rebinding 控制、SSH 与 proxy trust 限制。
修改
Jupyter 的自动 launch-token 体验:query 改为 fragment,随后换取 HttpOnly cookie。
采用
标准库生成 32 个随机字节,并对解码后的 credential 使用常数时间比较;该构造属于 OpenProgram 自身的实例 token 设计。
采用
Agent Zero 的 cookie、CSRF、Origin、WebSocket 组合校验,以及仅掩码 secret 更新。
修改
外部 proxy 或 VPN 可以增加传输与访问控制,但不能替代 OpenProgram token。
拒绝
认证关闭、query/localStorage token、明文 secret reveal、多用户账号、RBAC、内置 tunnel 和公网 relay。
05

最终认证与部署设计

每个 profile/state 实例只运行一个 Web 进程。Token 每次启动更换;浏览器用 fragment 单次引导后转派生的 HttpOnly cookie,原生客户端使用 Bearer header。

生成32 个随机字节,编码为 43 字符 unpadded base64url。
锁定并保存先持有 <state>/web.lock,再原子写 owner-only token 与无 token 的 access.json
派生并比较openprogram_owner_<owner16> 使用固定 HMAC domain;解码后只用 compare_digest
失效进程重启更换 token,原 Bearer 与 cookie 同时失效。

统一请求处理顺序

COMMON ASGI ORDER · NO ACTION BEFORE AUTHENTICATION Request HTTP · SSE · WS Host + scheme canonical parse request_origin Classify route · method credential source Origin / CSRF Sec-Fetch-Site safe / unsafe rules Authentication cookie · Bearer bootstrap body Owner scope owner_authority( principal_id) Route / stream WS accept occurs only here 403Host / scheme 403Origin / CSRF 401authentication 公共 static shell、ownership challenge、bootstrap 和最小 health 仍执行 Host 校验;只有 credential check 按 route policy 省略或内置。

Fragment 转 HttpOnly cookie

FRAGMENT BOOTSTRAP · TOKEN DOES NOT ENTER THE INITIAL HTTP REQUEST CLI Browser Web server 01 open /#token=<token> 02 GET / · fragment absent public static shell 03 read token into memory history.replaceState() 04 POST /api/auth/bootstrap · exact JSON ≤ 256 B 204 · Set-Cookie derived HMAC; HttpOnly; SameSite=Strict 后续 HTTP / SSE / WebSocket 使用 cookie;server restart 后 cookie 失效
Public allowlist

仅四个公共类别

静态 shell/asset、ownership challenge、bootstrap、最小 health。Shell 使用 CSP frame-ancestors 'none'X-Frame-Options: DENY

Browser cookie

CSRF 校验保留

GET/HEAD/OPTIONS 必须无副作用。Unsafe method 与 WS 要求 Origin 等于 request_origin;safe 请求只允许省略 Origin。

Native client

Header-only Bearer

HTTP、SSE 和原生 WS 使用 Bearer。不接受 query token;除 bootstrap 外,一旦存在 Authorization,错误 Bearer 不能回退 cookie。Bootstrap 出现 Authorization 时直接返回同一 401。

Listener ownership:<state>/web/access.json 冻结 bind、port、effective Origin 与 token fingerprint,但不包含 token。CLI 核对 worker PID/port 后,只向 GET /api/auth/challenge 发送新的 32 字节 nonce,并在本机验证 HMAC-SHA256(raw_token, "openprogram-web-challenge-v1\0" || nonce || "\0" || revision);token 不发送到被探测端口。

认证矩阵

HTTP、SSE 与 WebSocket 认证矩阵
请求形式CredentialOrigin失败结果
Cookie + unsafe HTTP必须等于 request_origin;missing 拒绝401403
Cookie + WebSocketaccept 前必须等于 request_origin;missing 拒绝Upgrade HTTP 401/403
Cookie + safe HTTP/SSE必须存在时必须相等;同源 navigation 可省略401403
Bearer HTTP/SSE必须可省略;存在时必须相等401403
Bearer WebSocketaccept 前必须原生客户端可省略;存在时必须相等Upgrade HTTP 401/403
Listener ownership challenge无 credential;nonce + 可选 revision可省略;存在时必须相等400403
Fragment bootstrap仅 body token;Authorization 拒绝等于 request_origin401403
SSH

后端保持 loopback

ssh -N -L 18100:127.0.0.1:18100 owner@remote-host

openprogram web auth-url \
  --base-url http://127.0.0.1:18100
Reverse proxy

公网域名使用 HTTPS

{
  "web": {
    "host": "127.0.0.1",
    "allowed_origins": ["https://agent.example.com"]
  }
}

# proxy preserves Host and Upgrade,
# overwrites X-Forwarded-Proto, clears unused forwarded headers,
# and disables SSE buffering
Origin 与 proxy trust:默认 loopback 自动加入当前端口的精确 localhost 与实际监听 literal;其他 Origin 必须在 config.json 显式配置。HTTP 只允许该 localhost、loopback、RFC 1918、IPv4/IPv6 link-local、IPv6 ULA 与 RFC 6598;其他地址和 DNS name 要求 HTTPS。每个请求只接受一个合法 Host;http/wshttps/wss 分别映射为相同浏览器 Origin。Uvicorn 使用 proxy_headers=False;OpenProgram 不信任 X-Forwarded-For,只接受原始 loopback peer 的单一 X-Forwarded-Proto。由 scheme + Host 构造的 request_origin 必须有效。

Secret 不可取回

Remove

删除两条 reveal

Account reveal route 返回 404;config-key status 保留掩码,但出现 reveal query 时返回 404。

Return

响应只含掩码

返回 has_valuemasked/masked_key。长度至少 12 时格式为 sk-…abc4,保证隐藏至少五位;短值固定八个圆点。

Replace / delete

两类动作分别定义

Config key 用 POST /api/config 替换、DELETE /api/config/key/{env} 删除;API-key account 用专用 update 替换、accounts/remove 删除整个 account。空值和 mask 都无效。

06

实现契约与验收

配置验证、token 安全保存和 fingerprint 计算完成后才接受连接。设计完成的判断依据是可执行行为测试,不是文档描述。

  1. Loopback HTTP、SSE、WS 无 credential 时失败。
  2. 正确 Bearer 在无 Origin 时成功;错误 token 无动作且返回相同 401。
  3. Fragment 在其他 fetch 前清除;bootstrap 只接受精确有界 JSON,拒绝混合 Authorization,并派生规定 HMAC cookie。
  4. Cookie unsafe HTTP 与 WS 拒绝 missing、opaque、cross-site Origin。
  5. Loopback、direct bind、proxy 都拒绝外部、重复、unspecified 与 multicast Host,并验证 HTTP/WS scheme 映射。
  6. 默认 loopback 只接受隐式 Origin;其他 SSH 本地端口必须显式配置。
  7. 非 loopback bind 缺少有效 Origin list 时拒绝启动;显式本地/overlay HTTP 范围带警告接受,其他地址拒绝。
  8. 关闭 Uvicorn proxy-header 改写;scheme 只信任原始 loopback peer,X-Forwarded-For 不改变信任,direct WS 与 Caddy WSS 校验 scheme 映射。
  9. 同 state directory 的第二进程不能修改 live token;失败清理验证 ownership。
  10. 重启更换 token,旧 Bearer 与 cookie 失效。
  11. Malformed Authorization 不能回退到有效 cookie。
  12. 静态 asset 与最小 health 不含 session、filesystem、credential metadata。
  13. CSP/X-Frame-Options 阻止 framing;认证与敏感 response 使用 no-store。
  14. 两种 reveal 请求为 404;config key 与 account 各自执行精确 replace/preserve/delete schema,8–11 字符使用固定 mask,frontend type 无明文 field。
  15. nginx/Caddy HTTPS 下 HTTP、SSE、WS 均能认证,backend 保持 loopback。
  16. Channel turn 保留 paired authority tier,不取得 Web owner authority。
  17. 同 hostname、不同端口的 profile server 使用不同 cookie 名称并独立认证。
  18. Listener ownership probe 核对 worker PID/port 与 access snapshot,只发送随机 nonce,验证 versioned token-HMAC proof,并拒绝 foreign listener、stale snapshot 及 port/fingerprint/proof/revision mismatch。
07

实现进度

三档严格分开。设计正文不是实现证据;只有当前生产代码与测试用于归类。

IMPLEMENTED process token / cookie / middleware fragment bootstrap / auth-url / health secret 不可取回 / BackendEndpoint 真实 listener HTTP / SSE / WS 验收 当前代码与测试有证据 PARTIAL browser 驱动的 asset / navigation audit nginx 与 Caddy smoke deployment 生产路径存在,验收范围未完成 EXPLICITLY OUT OF SCOPE 账号 / RBAC / project ACL OAuth 代替 token 内置 TLS / certificate relay / tunnel / insecure 产品边界明确排除
已实现
  • 默认 loopback、lifespan 与 per-profile owner
  • OwnerAuthState token、lock、cookie
  • canonical Origin 与共同 middleware
  • fragment bootstrap、auth-url、最小 health
  • proxy_headers=False 与 loopback-only forwarded scheme
  • 两条 plaintext reveal 已删除、严格 secret schema 与统一掩码
  • MCP 服务器凭证:存盘与响应序列化分离,env/headers/bearer/client secret 全掩码,编辑走 preserve/replace/delete,配置文件 0600 原子写
  • BackendEndpoint 驱动 TUI 与 MCP CLI 的 Bearer 认证
  • startup 报告 bind、Origin、fingerprint 与明文 HTTP 告警
  • 真实 Uvicorn listener 上的 HTTP/SSE/WS、bind-failure、轮换、双 profile 与泄露扫描验收
部分实现
  • browser 驱动的 asset/navigation audit
  • nginx 与 Caddy smoke deployment
明确不做
  • 账号、RBAC、项目权限
  • OAuth/SSO 替代 token
  • 内置 TLS 与证书管理
  • 公网 relay、托管 tunnel、pairing
  • 认证关闭与 plaintext reveal