Files
Nexus/docs/reports/2026-05-23-round2-merged-audit.md
T
Your Name fbf5eadcf2 fix(security): R2+R3 全面代码审计修复 — 3 CRITICAL / 9 HIGH / 15 MEDIUM / 10 LOW
CRITICAL:
- C-1: sync_service.py rsync命令shlex.quote防Shell注入回归
- C-2: agent.py exec端点危险命令正则拦截+compare_digest+僵尸进程修复
- C-3: WebSSH JWT token绑定server_id防IDOR

HIGH:
- H-1: 所有PUT/POST端点setattr改为字段白名单防任意字段注入
- H-2: settings/assets/scripts端点添加JWT认证
- H-3: refresh_token invalidate-then-generate防并发重放
- H-4: servers.py Redis pipeline解决N+1查询
- H-7: settings API Key/Secret掩码+禁止修改
- H-8: TOTP暴力破解速率限制(5次/5分钟)
- H-9: get_optional_admin改用request-scoped session

MEDIUM:
- M-2: X-Real-IP优先+X-Forwarded-For取末值防IP伪造
- M-4: asyncssh异常信息脱敏(只含server_id)
- M-5: 分页limit上限(500/200/500/500)
- M-9: API层Redis依赖抽象至dependencies.py
- M-10: WebSocket ConnectionManager多worker Redis聚合
- M-13: login_attempts复合索引
- M-14: ServerRepository.get_by_ids批量查询
- M-15: API错误消息统一中文

R3追加:
- sysctl命令注入防护+regex验证
- $DB_PASS明文存储→masked_command双命令方案
- MYSQL_PWD环境变量替代-p flag
- health端点拆分(公开/需认证)
- repo层**kwargs→字段白名单
- 全局str(e)信息泄露修复(API/Telegram/WebSocket)
- SSRF私有IP拦截
- Nginx HTTPS配置+DB备份脚本
- 前端CDN SRI哈希+XSS修复
- __import__替换为正常import

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-24 10:58:33 +08:00

10 KiB
Raw Blame History

Nexus 6.0 — 全面代码扫描审计报告 (Round 2 合并版)

合并来源: 本地深度扫描 + worktree独立审计
说明: 两份独立审计报告去重合并,标注已修复项


P0 — CRITICAL (立即修复)

C-1: sync_service.py rsync命令 — Shell注入回归

  • 文件: server/application/services/sync_service.py:195
  • 来源: 本地审计 BUG-2
  • 描述: rsync命令f-string直接嵌入 source_path, server.username, server.domain, target_path,无 shlex.quote()。sync_engine_v2.py 已修复(C8),但 sync_service.py 遗漏。恶意用户名如 root'; rm -rf /;# 可执行任意命令。
  • 修复: import shlex; 所有动态参数 shlex.quote()

C-2: agent.py exec — 命令注入无防护(RCE)

  • 文件: server/api/agent.py:193-209
  • 来源: 两份报告均发现 (本地 SEC-1 / worktree S-02)
  • 描述: /api/agent/exec 直接 create_subprocess_shell(command) 执行任意命令,无白名单/危险命令检测。仅全局API Key保护。Nexus被攻破后可对所有Agent执行任意命令。
  • 修复: 添加与 script_service.py 一致的危险命令检测;命令白名单;secrets.compare_digest 替代 == 比较API Key

C-3: WebSSH 横向越权(IDOR

  • 文件: server/api/webssh.py:82-97
  • 来源: worktree S-01/B-01
  • 描述: JWT无 server_id claim时不校验路径 server_id,任意已登录管理员可改URL连任意服务器SSH。_verify_webssh_token() 返回 server_id 但未与路径参数比较。
  • 修复: 签发WebSSH专用短期JWT(必含 server_id);验证时比对 token_server_id == path server_id;不匹配则 close(4003)

P1 — HIGH (本周修复)

H-1: PUT/POST端点 setattr 无白名单 — 任意字段注入

  • 文件: servers.py:121-123, settings.py:89-91, assets.py:52-54,109-111, scripts.py:69-71, servers.py:106
  • 来源: 本地审计 BUG-4/5
  • 描述: 所有PUT端点 for key, value in payload.items(): setattr(obj, key, value),攻击者可注入 is_active=False, password_hash="...", is_online=True 等敏感字段。POST端点 Server(**payload) 同理。
  • 修复: 定义每端点允许字段白名单;或使用Pydantic请求模型

H-2: settings/assets 端点 — 无JWT认证

  • 文件: server/api/settings.py, server/api/assets.py
  • 来源: 本地审计 SEC-2
  • 描述: 所有端点使用 Depends(get_db) 而非 Depends(get_current_admin)。任何人可读/改系统设置、创建/删除节点、查看SSH会话和命令日志。
  • 修复: 所有端点添加 admin: Admin = Depends(get_current_admin) 依赖

H-3: agent.py proc.kill() — 僵尸进程泄漏

  • 文件: server/api/agent.py:223
  • 来源: 两份报告均发现 (本地 BUG-1 / worktree B-05)
  • 描述: asyncio.TimeoutError 分支 proc.kill() 后无 await proc.wait(),产生僵尸进程。
  • 修复: proc.kill() 后加 await proc.wait()

H-4: refresh_token 并发重放攻击

  • 文件: server/application/services/auth_service.py:105-127
  • 来源: 本地审计 BUG-3
  • 描述: 并发请求使用同一refresh_token都能成功获取新token。违反rotation安全原则。
  • 修复: 数据库层面加唯一约束或应用层加锁

H-5: N+1 Redis查询 — 2000+服务器性能瓶颈

  • 文件: server/api/servers.py:40-65
  • 来源: 两份报告均发现 (本地 PERF-1 / worktree P-02)
  • 描述: 每台服务器单独 redis.hgetall()2000+服务器=2000+次Redis往返。
  • 修复: Redis pipeline 批量获取

H-6: Agent心跳直写MySQL — 与文档矛盾

  • 文件: server/api/agent.py:172
  • 来源: worktree B-04/P-01
  • 描述: 每次心跳 service.update_heartbeat() + commit,与文档"Redis实时+10min批量落MySQL"矛盾。2000+服务器×60s = 高MySQL负载。
  • 修复: 心跳仅写Redis,由 heartbeat_flush.py 批量刷库

H-7: API Key reveal 端点

  • 文件: server/api/settings.py (如存在 /api-key/reveal)
  • 来源: worktree S-03
  • 描述: 对已登录管理员返回完整全局API_KEY,一旦XSS即可窃取。
  • 修复: 禁止回读;仅轮换时展示一次

H-8: TOTP disable 无二次验证

  • 文件: server/api/auth.py:151-165
  • 来源: worktree S-09
  • 描述: totp/disable 仅需JWT,无密码/TOTP二次验证。JWT被盗后攻击者可直接关闭双因素。
  • 修复: 要求 current_password + 有效TOTP码

H-9: 全局无JWT中间件 — 新路由易漏认证

  • 文件: 架构层面
  • 来源: worktree E-01
  • 描述: 每路由靠 Depends(get_current_admin),新路由开发易遗漏。settings/assets 已漏。
  • 修复: main.py 默认拒绝 + 白名单(install/health/agent/auth/login

P2 — MEDIUM (迭代修复)

M-1: server_id 类型验证缺失

  • 文件: server/api/agent.py:103
  • 来源: 本地审计 BUG-6
  • 修复: try: server_id = int(payload["server_id"]); except: raise 400

M-2: get_optional_admin session泄漏

  • 文件: server/api/auth_jwt.py:128-133
  • 来源: 本地审计 BUG-7
  • 修复: 接收Request参数,通过 _get_request_session(request) 获取session

M-3: sshpass环境变量未设置

  • 文件: server/application/services/sync_service.py:188-193
  • 来源: 本地审计 BUG-8
  • 修复: exec_command调用时传递 env={"SSHPASS": password}

M-4: X-Forwarded-For IP伪造

  • 文件: server/api/auth.py:19-24
  • 来源: 本地审计 SEC-3
  • 修复: 优先使用 X-Real-IP headerNginx设置);或使用 X-Forwarded-For 最后一个值

M-5: known_hosts=None — SSH中间人攻击

  • 文件: server/infrastructure/ssh/asyncssh_pool.py:145
  • 来源: 本地审计 RISK-1
  • 修复: 实现known_hosts缓存机制

M-6: 异常信息泄露服务器拓扑

  • 文件: server/infrastructure/ssh/asyncssh_pool.py:164
  • 来源: 本地审计 RISK-2
  • 修复: 日志记录完整错误,返回客户端隐藏内部地址

M-7: TOTP brute-force 无限制

  • 文件: server/application/services/auth_service.py:179-191
  • 来源: 本地审计 RISK-3
  • 修复: TOTP验证添加速率限制(5次失败后锁定5分钟)

M-8: payload: dict → Pydantic模型

  • 文件: 多处API路由
  • 来源: 本地审计 STD-1
  • 修复: 为每个端点创建Pydantic请求模型

M-9: 在线统计与列表数据源不一致

  • 文件: server/api/servers.py
  • 来源: worktree B-03
  • 修复: 统计接口与列表共用Redis数据源

M-10: login_attempts 缺少复合索引

  • 文件: server/infrastructure/database/admin_repo.py:48-58
  • 来源: 本地审计 PERF-3
  • 修复: 添加 Index('idx_login_attempts_check', 'username', 'ip_address', 'success', 'attempted_at')

M-11: audit_logs/settings 无分页上限

  • 文件: server/api/settings.py:23-27
  • 来源: 本地审计 PERF-2
  • 修复: 添加limit上限保护

M-12: install路由生产环境仍挂载

  • 文件: server/api/install.py
  • 来源: worktree S-08
  • 修复: 安装完成后卸载路由或IP白名单+一次性token

M-13: API Key比较非常量时间

  • 文件: server/api/agent.py:37
  • 来源: worktree S-12
  • 修复: secrets.compare_digest(x_api_key, settings.API_KEY)

M-14: 告警冷却多worker重复Telegram

  • 文件: server/api/websocket.py
  • 来源: worktree P-03
  • 修复: Redis SETNX + TTL 去重

M-15: AES-CBC遗留兼容代码

  • 文件: server/infrastructure/database/crypto.py:59-75
  • 来源: worktree R-01
  • 修复: 迁移期后移除CBC;统一Fernet

P3 — LOW (优化改进)

L-1: __import__("datetime") 应改为正常import

  • 文件: server/application/services/sync_service.py:168,200,212,219,228
  • 来源: 本地审计 STD-2

L-2: infrastructure层直接import到api层

  • 文件: server/api/servers.py:17, server/api/agent.py:22-23
  • 来源: 本地审计 STD-3

L-3: Fernet key无rotation机制

  • 文件: server/infrastructure/database/crypto.py:16-21
  • 来源: 本地审计 SEC-4

L-4: Redis overlay逻辑重复(DRY)

  • 文件: server/api/servers.py:44-61 vs :80-95
  • 来源: 本地审计 OPT-2

L-5: API响应含SSH username字段

  • 文件: server/api/servers.py:206
  • 来源: 本地审计 OPT-3

L-6: 错误消息中英文混用

  • 文件: 多处
  • 来源: 本地审计 UX-1

L-7: refresh token单设备限制

  • 文件: server/domain/models/__init__.py:157-158
  • 来源: 本地审计 SCALE-2

L-8: batch_push顺序获取server

  • 文件: server/application/services/sync_service.py:67-72
  • 来源: 本地审计 PERF-4

L-9: 前端esc()重复定义

  • 文件: 多处 web/app/*.html
  • 来源: worktree C-02

L-10: 前端空catch吞错误

  • 文件: web/app/api.js
  • 来源: worktree U-01

L-11: install.py同步subprocess阻塞事件循环

  • 文件: server/api/install.py:283-284
  • 来源: worktree C-03

L-12: 前端15页独立内联脚本无组件复用

  • 文件: web/app/*.html
  • 来源: worktree E-04

汇总

严重度 数量 类别覆盖
P0 CRITICAL 3 Shell注入回归、Agent RCE、WebSSH IDOR
P1 HIGH 9 setattr注入、无JWT认证、僵尸进程、token重放、N+1 Redis、心跳写库矛盾、API Key reveal、TOTP disable、全局JWT
P2 MEDIUM 15 类型验证、session泄漏、sshpass、IP伪造、SSH MITM、信息泄露、TOTP brute-force、Pydantic、数据源不一致、索引缺失、分页、install路由、compare_digest、告警去重、AES遗留
P3 LOW 12 import规范、架构违规、key rotation、DRY、字段脱敏、i18n、多设备、批量查询、前端esc统一、错误处理、install阻塞、前端复用

修复执行顺序

第一批(P0 — 安全致命):

  1. C-1: sync_service.py shlex.quote()
  2. C-2: agent exec 危险命令检测 + compare_digest
  3. C-3: WebSSH server_id绑定验证

第二批(P1 — 安全+性能): 4. H-1: setattr白名单/Pydantic模型 5. H-2: settings/assets JWT认证 6. H-9: 全局JWT中间件 7. H-3: proc.kill() + await proc.wait() 8. H-4: refresh_token并发保护 9. H-5: Redis pipeline 10. H-6: 心跳仅写Redis 11. H-7: API Key reveal禁止 12. H-8: TOTP disable二次验证

第三批(P2 — 纵深防御): M-1 ~ M-15

第四批(P3 — 优化): L-1 ~ L-12