Files
crypto_okx/docs/审计报告-中控实例全方位-2026-10-07.md
T
2026-10-07 16:19:18 +08:00

144 lines
8.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 审计报告:中控 Bridge + 实例全方位(2026-10-07)
> 基线提交:`a23fb7c`(含数据统计页与实盘说明同步)
> 对照:`docs/审计报告-高危修复-2026-10-07.md`(币本位高危闭环)
## 1. 范围
| 范围 | 内容 |
| --- | --- |
| 本仓库实例侧 | `app.py`、`lib/options/**`、`lib/instance/**`、`lib/hub/**`(Bridge)、`lib/sim/**`、`lib/env/**`、备份/远程更新 |
| 本仓库中控侧 | 仅有 **实例 Bridge**(`/api/hub/*`、`/hub_sso`);**中控前端/常驻进程**在独立仓库(如 `crypto_okx_hub`),本轮未审其 SSRF/SSE 实现 |
| 方法 | 三路并行静态审阅(Bridge 权限、资金路径回归、Web 鉴权/XSS/CSRF)+ 人工复核关键代码 + 对照 10-07 高危修复项 |
## 2. 总览
| 级别 | 数量 | 说明 |
| --- | --- | --- |
| Critical | 1 | Bridge Token 明文进 env 设置页 → 等价远程 root |
| High | 6 | 平仓后卖币回归;settings 认 Bridge Token;7 天 embed_sso;备份 tar slip;CSRF/破坏性 GET;`/options/guide` 缺模块 500 |
| Medium | 9 | 监控/条件单失败语义;close_preview 时延;Webhook;登录无限速;复盘图;journal 删路径;frame-ancestors=*;version 泄路径 |
| Low | 若干 | 密码策略、进程内 SECRET 回退、局部 XSS、SSO 可重放至过期、settings Token 用 `==` |
**币本位 10-07 Critical/High 主路径**:开仓增量、卖回封顶、粉尘桥、`sweep_spot_after_options_flat`、中控条件单持仓上限等 **仍在**;本地相关单测此前已通过。
**回归**:`maybe_sell_spot_after_close` 未与 sweep 对齐。
## 3. Critical
### C1 · `HUB_BRIDGE_TOKEN` 对已登录会话明文可见
| | |
| --- | --- |
| 位置 | `lib/env/env_schema.py`(`SENSITIVE_EXACT` 未含 `HUB_BRIDGE_TOKEN`);`/api/settings/env`;设置页 JS 明文输入框 |
| 证据 | `_is_sensitive` 仅匹配 `APP_PASSWORD` / `*_SECRET` / `*_API_KEY` 等;`HUB_BRIDGE_TOKEN` 走明文 `current` |
| 影响 | 任意已登录或持有 7 天 `embed_sso` 的会话可复制 Token,进而无 Cookie 调用 `/api/hub/update`(git pull+重启)、`/api/hub/backup/download`(含 `.env`)、平仓/条件单等 |
| 建议 | 将 `HUB_BRIDGE_TOKEN`(及 `WECHAT_WEBHOOK`)列入 `SENSITIVE_EXACT`;UI 仅显示掩码;复制走一次性确认;拆分 read/trade/admin Token |
## 4. High
### H1 · 平仓后卖币:持仓查询失败/`None` 当空仓(回归)
| | |
| --- | --- |
| 位置 | `lib/options/options_coin_open_lib.py` · `maybe_sell_spot_after_close` |
| 证据 | `fetch_option_positions(ex) or []`;`except: pass` 后仍调用 `sell_residual_after_option_flat` |
| 对照 | 同文件 `sweep_spot_after_options_flat` 已正确拒绝 `None`/异常 |
| 调用链 | 买一平仓 / close_exec / monitor 同步卖币 |
| 影响 | API 抖动时可能市价卖掉桥/抵押币,期权仓仍在 |
| 建议 | 与 sweep 对齐;加单测 |
### H2 · Bridge Token 可认证大部分 `/api/settings/*`
| | |
| --- | --- |
| 位置 | `lib/instance/instance_settings_register.py` · `_api_login_required` |
| 证据 | `X-Hub-Token == HUB_BRIDGE_TOKEN` → `allowed=True`;仅拦截 env **写入**,不拦 restart / backup restore / download |
| 影响 | Token 即可恢复备份(含 `.env`)、PM2 重启,无需实例密码 |
| 建议 | Bridge 只走 `/api/hub/**`;设置类 API 仅 session/embed_sso |
### H3 · `embed_sso` 默认 7 天且可进 URL
| | |
| --- | --- |
| 位置 | `hub_bridge_register.py` `/hub_sso`;`app.py` `login_required` |
| 影响 | Referer/历史/日志泄露 → 长期全权 UI(含开仓、改密、恢复备份) |
| 建议 | TTL 缩至数小时;禁止 query 传参(仅 header/sessionStorage);绑定 Origin |
### H4 · 备份恢复 `tar.extractall` 无成员路径校验
| | |
| --- | --- |
| 位置 | `lib/instance/backup_lib.py` · `restore_backup` |
| 影响 | 已认证用户恢复恶意包时可写穿临时目录(tar slip) |
| 建议 | Python 3.12+ `filter="data"`;或校验成员路径不越出 `tmp` |
### H5 · CSRF:`SameSite=None` + 无 CSRF Token;破坏性 GET
| | |
| --- | --- |
| 位置 | `app.py` Cookie SameSite 默认 None;`/del_key/<id>` GET 删除 |
| 影响 | 跨站可借会话触发恢复/改密等;`<img src=/del_key/…>` 可删关键位 |
| 建议 | 状态变更一律 POST + CSRF/Origin 校验;删除改 POST |
### H6 · `/options/guide` 引用不存在的 `lib.hub.hub_strategy_lib`
| | |
| --- | --- |
| 位置 | `lib/options/options_register.py`(约 441 行) |
| 证据 | 仓库内无 `hub_strategy_lib.py`;同能力已在 `lib/common/markdown_html_lib.py` |
| 影响 | 打开期权说明页直接 ImportError/500(可用性 High,非资金) |
| 建议 | 改为 `from lib.common.markdown_html_lib import render_markdown_html` |
## 5. Medium
| ID | 主题 | 位置 | 要点 |
| --- | --- | --- | --- |
| M1 | 监控持仓拉取失败 → `[]` | `options_monitor_lib.py` | 目标监控可能被标 expired,自动化出场中断 |
| M2 | 条件单 exit `or []` / `machine_has_option_position` 视 `None` 为空 | `options_cond_order_lib.py` | 查询失败可能误结束条件单 |
| M3 | 中控快照仍算 `close_preview` | `options_hub_lib.py` | 利于流动性展示,加重超时风险(相对 10-07「关闭 preview」有回退) |
| M4 | `WECHAT_WEBHOOK` 未脱敏 | env schema | 登录用户可读完整 webhook |
| M5 | `/login` 无限速 | `app.py` | 密码爆破 |
| M6 | 复盘静态图无 login | `options_review_register.py` | 依赖不可猜测文件名 |
| M7 | journal 删除路径未限制在 upload 根下 | `journal_images_lib.py` | DB 被投毒时可删库外文件 |
| M8 | `HUB_EMBED_FRAME_ANCESTORS=*` | `hub_bridge_auth.py` | 任意父页可嵌实例(点击劫持面) |
| M9 | `/api/hub/version` 返回本机 `repo` 绝对路径 | `instance_update_lib.py` | 信息泄露(需 Bridge Token) |
## 6. Low / 运维注意
- Bootstrap 空密码时写入 `admin123`(`scripts/bootstrap_deploy_secrets.py`)— 上线后必须改密
- `APP_AUTH_DISABLED=true` 关闭全部鉴权 — 仅本地调试
- `FLASK_SECRET_KEY` 未配置时进程随机 — 重启会话失效
- 改密最短 6 位、明文比对 `.env`
- 复盘/统计主路径有 `escapeHtml`;`options_panel.js` 等对交易所字段拼接仍有局部 XSS 面
- 远程更新依赖固定脚本 + `git pull`:Token 泄露即供应链风险(与 C1/H2 叠加)
- SSO 签名令牌在过期前可重放(无一次性消费);settings 侧 Token 比对用 `==` 而非 `hmac.compare_digest`
- `lib.hub.hub_auth` 在本仓不存在,settings 鉴权依赖 ImportError 回落(行为易混淆)
## 7. 已验证仍稳健(摘要)
- Bridge 写路径:禁市价平、中控仅全平、条件单创建有持仓上限与本机有仓拒绝
- SSO `next` 防开放重定向(`_safe_next_path`)
- 备份文件名白名单 + 路径限制在 backup 目录内
- Bridge Token 校验用 `hmac.compare_digest`
- 币本位:买币增量、卖回 `coin_amount` 封顶、粉尘桥 `positions_ok`、sweep 失败不卖
- SQLite WAL + busy_timeout;条件单/目标出场多数已「先关连接再网络」
- env 对 API Key / Passphrase / App 密码有脱敏
## 8. 建议修复优先级
1. **立刻**:C1 脱敏 `HUB_BRIDGE_TOKEN`;H1 对齐 `maybe_sell_spot_after_close`;H6 guide 导入修正
2. **本周**:H2 收紧 settings 对 Bridge Token;H3 缩短 embed_sso;H4 tar filter;H5 CSRF + `/del_key` POST
3. **随后**:M1–M3 失败语义统一;M4–M9 加固;评估中控侧独立仓库 SSRF/实例 URL 白名单
## 9. 结论
- **交易资金主路径**:10-07 高危大多仍成立,但 **平仓后卖币入口存在明确 High 回归**,应优先修。
- **中控/实例权限模型**:单一长效 `HUB_BRIDGE_TOKEN` + 明文进设置页 + 设置 API 认 Token,是本轮 **最大系统性风险**(Critical)。
- **中控 UI 仓库**未纳入本轮;实例 Bridge 与中控控制面需分开再审一轮。
修复后建议:再跑一轮 Bugbot(未提交变更)+ `tests.test_spot_dust_and_sell_cap` 等币本位单测,并人工测「持仓 API 失败时不卖币」。
## 10. 审阅来源
并行静态审阅(结果已并入上文):[Bridge 权限](f31789fc-cb2a-4838-ba28-777fbdc07de0)、[资金路径回归](b0c41cf8-fa1c-4a7c-8840-b2ba60fceb15)、[Web 鉴权/CSRF](6c69483e-2340-47c0-bdb8-0d02473dbfbf)。