同机访问
CLI 自动打开带 fragment token 的 loopback URL。
同机、局域网或 VPN、SSH 隧道、所有者域名与 HTTPS 反向代理全部支持。 每次 Web 启动生成实例 token;HTTP、SSE、WebSocket 使用同一认证规则; OpenProgram 不运营公网中转,不增加账号、RBAC 或项目权限。
Web UI 是一个完整的所有者管理权限边界。多人协作继续使用 channel speaker 归因与受限 capability,不转化为 Web 账号。
CLI 自动打开带 fragment token 的 loopback URL。
必须显式配置完整、精确的 allowed_origins。
浏览器连接本地转发端口,SSH 提供传输加密。
web.host,实例 token 继续认证。nginx 或 Caddy 在同机终结 HTTPS,保留公网 Host。
Owner process token、canonical Origin、fragment bootstrap、共同 HTTP/WS 认证边界、auth-url 和最小 health 已进入生产路径;secret 不可取回与完整部署验收仍未完成。
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。
两条 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 验收。
| 当前对象 | 已实现 | 缺失或风险 |
|---|---|---|
OwnerAuthState | token、lock、owner-only files、access snapshot、cookie、常数时间比较 | 真实 bind-failure、restart 与 multi-profile 验收缺失 |
| Canonical Origin | effective Origin、非 loopback fail-closed、本地 HTTP 网段 | startup 输出尚缺完整字段与直接 HTTP 警告 |
OwnerAuthMiddleware | HTTP/WS、cookie/Bearer、Host/Origin/CSRF、owner authority | 缺少独立 SSE 与真实 browser WS 验收 |
| Fragment bootstrap | backend、frontend gate、同步清除、无 Web Storage、auth-url | 缺少 browser-level end-to-end 验收 |
| Reverse proxy | proxy_headers=False 与 loopback-only forwarded scheme | nginx/Caddy HTTPS、WS、SSE smoke 未测试 |
| Provider secret | 部分响应默认掩码 | 两个 reveal 路径返回明文 |
/healthz | 只返回 status=ok;详细字段位于受保护的 /api/diagnostics | 完整 response-class cache audit 尚未完成 |
范围包括现有参考语料与具备远程 Web、认证、反向代理或 secret 处理能力的补充系统;目标能力不存在时明确标为不适用。
| 系统 | 默认与认证 | 远程方式 | 采用 | 拒绝或不适用 |
|---|---|---|---|---|
| OpenClaw | loopback;外部需要认证;显式 Origin | SSH、反向代理、其他外部网络方式 | fragment、Host/Origin、proxy trust | tokenless identity 替代 |
| Jupyter Server | Notebook 4.3 默认 token;首次访问转 cookie | SSH、HTTPS public server | 自动 token → cookie 体验 | query token、密码模式 |
| Hermes Agent | loopback;外部 bind 强制 auth provider 并 fail closed | session cookie;单次 WS ticket | 外部 fail-closed、secret redaction | auth-provider 账号、第二套 ticket、reveal |
| Agent Zero | 本地;可选单组登录;cookie + CSRF | 反向代理、VPS、内置 tunnel | cookie/CSRF/Origin/WS、secret mask | 可关闭认证、内置公网 tunnel |
| OpenHands | session API key;HTTP/WS | SSH、nginx/HTTPS | 实例 key、loopback backend | 公共 HTML/browser storage 暴露 token、明文 secret retrieval |
| opencode | loopback;未设置密码时无认证 | 外部 host、CORS origins;另有 WS ticket | loopback default | 可选认证、第二套 WS ticket |
| Open WebUI | 账号、角色、JWT/cookie | nginx/Caddy、WS、SSE | proxy、Upgrade、SSE buffering 配置 | 账号、group、RBAC |
| Dify | account/workspace/role | 反向代理 | credential obfuscation 与替换语义 | tenant 与 role 层 |
| LibreChat | 注册、JWT、角色与 ACL | nginx HTTPS/WS | proxy 细节 | 用户身份数据模型 |
| AnythingLLM | 单用户或多用户;单用户密码可选 | Docker port | 单一 owner credential 概念 | 可选认证、role system |
| AutoGen Studio | loopback;默认无认证;可选 OAuth/JWT | research prototype | loopback default | query/localStorage token、post-accept auth |
| SWE-agent | 当前仓库提供命令行 agent | 无 owner Web control UI | 记录能力缺失 | 远程安全设计不适用 |
| pi-mono / pi-ai | TUI、SDK、RPC/provider transport | 无 packaged owner Web server | 记录能力缺失 | 远程 Web ownership 不适用 |
| WeClaw | WeChat gateway + HTTP API | listen address 可配 | 记录外部 HTTP 与 Web UI 的区别 | 浏览器 owner UI 不存在 |
| Codex CLI | app-server 与实验性 WS | service-mediated pairing/remote control | 记录协议差异 | 不采用 relay 型 remote control |
| 类型 | 框架或能力 | OpenProgram 处理 |
|---|---|---|
| 实例 credential | Jupyter、OpenClaw、OpenHands | 采用:一个 owner,一个根密钥,两种传输凭证形式 |
| 应用账号 | Open WebUI、Dify、LibreChat、AnythingLLM | 不采用:不需要注册、role、resource ACL |
| 托管远程控制 | pairing、hosted tunnel、relay service | 不采用:OpenProgram 不运营外部服务 |
最终设计只保留完成当前需求所需的一个根密钥(实例 token)、两种传输凭证形式(Bearer header 与 profile 作用域 HttpOnly cookie)、一套浏览器 bootstrap 和一组 HTTP/WS/SSE 认证规则。
每个 profile/state 实例只运行一个 Web 进程。Token 每次启动更换;浏览器用 fragment 单次引导后转派生的 HttpOnly cookie,原生客户端使用 Bearer header。
<state>/web.lock,再原子写 owner-only token 与无 token 的 access.json。openprogram_owner_<owner16> 使用固定 HMAC domain;解码后只用 compare_digest。静态 shell/asset、ownership challenge、bootstrap、最小 health。Shell 使用 CSP frame-ancestors 'none' 与 X-Frame-Options: DENY。
GET/HEAD/OPTIONS 必须无副作用。Unsafe method 与 WS 要求 Origin 等于 request_origin;safe 请求只允许省略 Origin。
HTTP、SSE 和原生 WS 使用 Bearer。不接受 query token;除 bootstrap 外,一旦存在 Authorization,错误 Bearer 不能回退 cookie。Bootstrap 出现 Authorization 时直接返回同一 401。
<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 不发送到被探测端口。| 请求形式 | Credential | Origin | 失败结果 |
|---|---|---|---|
| Cookie + unsafe HTTP | 必须 | 等于 request_origin;missing 拒绝 | 401 或 403 |
| Cookie + WebSocket | accept 前必须 | 等于 request_origin;missing 拒绝 | Upgrade HTTP 401/403 |
| Cookie + safe HTTP/SSE | 必须 | 存在时必须相等;同源 navigation 可省略 | 401 或 403 |
| Bearer HTTP/SSE | 必须 | 可省略;存在时必须相等 | 401 或 403 |
| Bearer WebSocket | accept 前必须 | 原生客户端可省略;存在时必须相等 | Upgrade HTTP 401/403 |
| Listener ownership challenge | 无 credential;nonce + 可选 revision | 可省略;存在时必须相等 | 400 或 403 |
| Fragment bootstrap | 仅 body token;Authorization 拒绝 | 等于 request_origin | 401 或 403 |
ssh -N -L 18100:127.0.0.1:18100 owner@remote-host openprogram web auth-url \ --base-url http://127.0.0.1:18100
{
"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
localhost 与实际监听 literal;其他 Origin 必须在 config.json 显式配置。HTTP 只允许该 localhost、loopback、RFC 1918、IPv4/IPv6 link-local、IPv6 ULA 与 RFC 6598;其他地址和 DNS name 要求 HTTPS。每个请求只接受一个合法 Host;http/ws 与 https/wss 分别映射为相同浏览器 Origin。Uvicorn 使用 proxy_headers=False;OpenProgram 不信任 X-Forwarded-For,只接受原始 loopback peer 的单一 X-Forwarded-Proto。由 scheme + Host 构造的 request_origin 必须有效。Account reveal route 返回 404;config-key status 保留掩码,但出现 reveal query 时返回 404。
返回 has_value 与 masked/masked_key。长度至少 12 时格式为 sk-…abc4,保证隐藏至少五位;短值固定八个圆点。
Config key 用 POST /api/config 替换、DELETE /api/config/key/{env} 删除;API-key account 用专用 update 替换、accounts/remove 删除整个 account。空值和 mask 都无效。
配置验证、token 安全保存和 fingerprint 计算完成后才接受连接。设计完成的判断依据是可执行行为测试,不是文档描述。
三档严格分开。设计正文不是实现证据;只有当前生产代码与测试用于归类。
OwnerAuthState token、lock、cookieproxy_headers=False 与 loopback-only forwarded schemeenv/headers/bearer/client secret 全掩码,编辑走 preserve/replace/delete,配置文件 0600 原子写BackendEndpoint 驱动 TUI 与 MCP CLI 的 Bearer 认证