# 外网攻击面加固 Backlog(audit_only 产出) **日期**:2026-06-06 **来源**:[`2026-06-06-external-attack-surface-audit.md`](2026-06-06-external-attack-surface-audit.md) **状态**:BL-01~BL-07 **已实施/已接受**;BL-08 **不需要**(运维确认);BL-06 **已实施**(2026-06-07) --- ## P2 — 建议优先 ### BL-01 收紧 `PUBLIC_PREFIXES` 前缀匹配 ✅ 已实施 | 字段 | 内容 | |------|------| | 问题 | EXT-01 `/health/detail`、EXT-02 `bing-wallpapers/sync` 被前缀误放行 | | 方案 A | 将 `/health` 改为精确路径列表;`/api/settings/bing-wallpapers` 仅匹配 GET(或拆路由前缀) | | 方案 B | `_is_public_path` 改为精确匹配 + 显式允许方法 | | 涉及文件 | `server/api/auth_jwt.py` | | 验收 | 无 JWT 时 `GET /health/detail` → 401;`POST .../sync` → 401 | | 回滚 | 恢复 `PUBLIC_PREFIXES` 元组 | ### BL-02 `/health/detail` 强制鉴权(防御纵深) ✅ 已实施 | 字段 | 内容 | |------|------| | 问题 | 非 `/api/` 路径不走 JwtAuthMiddleware | | 方案 | handler 内显式 `if admin is None: raise 401`;或把 detail 移到 `/api/health/detail` | | 涉及文件 | `server/api/health.py`、`server/main.py` DbSessionMiddleware 路径列表 | | 验收 | 生产探测 401 | ### BL-03 `bing_wallpapers_sync` 拒绝 `admin is None` ✅ 已实施 | 字段 | 内容 | |------|------| | 方案 | `Depends(get_current_admin)` 返回 None 时 raise 401(与 BL-01 双保险) | | 涉及文件 | `server/api/settings.py` | --- ## H — 信息暴露与运维 ### BL-04 生产关闭 OpenAPI / Swagger / ReDoc ✅ 已实施 | 字段 | 内容 | |------|------| | 问题 | EXT-03 全 API schema 公网可读 | | 方案 A | `FastAPI(..., docs_url=None, redoc_url=None, openapi_url=None)` | | 方案 B | Nginx/1Panel `location` deny 或 internal only | | 验收 | `GET /openapi.json` → 404 | | 备注 | 开发环境可保留文档 | ### BL-05 已安装后隐藏 install 指纹 ✅ 已实施 | 字段 | 内容 | |------|------| | 实现 | `_raise_not_found_if_locked()`;全部 install 端点锁定后 404 | | 涉及文件 | `server/api/install.py`、`tests/test_install_locked_404.py` | | 验收 | 锁定后所有 `/api/install/*` → 404 | ### BL-06 Agent per-server key 迁移 ✅ 已实施 | 字段 | 内容 | |------|------| | 问题 | global `API_KEY` legacy 回退(原 risk-acceptance 接受项 2) | | 方案 | 移除 `agent.py` / `servers.py` / `script_service.py` 中 global 回退;强制 per-server key | | 实施日期 | 2026-06-07(生产 0 台子机窗口) | | 验收 | `tests/test_agent_per_server_key.py`;global key 打 heartbeat → 401 | | changelog | `docs/changelog/2026-06-07-agent-per-server-key-enforced.md` | ### BL-07 WebSocket 外网探测与反代 ✅ 已澄清/接受 | 字段 | 内容 | |------|------| | 原问题 | 外网无 token 探测见 HTTP 403,误以为反代未转发 WS | | 结论 | 直连 8600 同为 403;1Panel 反代已带 Upgrade;**有效 JWT 可连** `/ws/alerts`、`/ws/sync` | | 根因 | `websocket.close(4001/4401)` 在 `accept()` 前 → 黑盒见 HTTP 403,非安全缺陷 | | 证据 | [`2026-06-06-external-hardening-deploy-verification.md`](2026-06-06-external-hardening-deploy-verification.md) §WebSocket | | 动作 | 更新 `security_probe_external.sh`:无 token 拒绝即 PASS;**无需改 Nginx** | ### BL-08 全站 IP 白名单 ❌ 不需要 | 字段 | 内容 | |------|------| | 决定 | 2026-06-06 运维确认:**不实施** | | 理由 | 单人自用;2000+ 子机 Agent 需放行 `/api/agent/*`,全站白名单 ROI 低 | | 维持 | 仅 login IP allowlist(`LOGIN_ALLOWLIST_ENABLED`)即可 | --- ## 验证清单(修复批次) ```bash NEXUS_PROBE_BASE=https://api.synaglobal.vip bash scripts/security_probe_external.sh # 期望:health/detail 401;bing sync 401;openapi 404(若 BL-04) bash scripts/local_verify.sh ``` --- ## 不建议本轮做 | 项 | 原因 | |----|------| | WS ticket 首帧鉴权 | 单人运维 ROI 低,已接受 | | 登录暴破 CAPTCHA | 已有 15min 锁定 | | 关闭 `/agent/install.sh` 公网 | 破坏远程安装流程 |