# Round 2 全面代码审计修复报告

**日期**: 2026-05-23
**范围**: 全部8类别深度扫描 (功能性缺陷/安全漏洞/代码规范/安全风险/性能/可用性/可扩展性/优化)

## 修复汇总

| 严重度 | 数量 | 状态 |
|--------|------|------|
| CRITICAL | 3 | 全部修复 |
| HIGH | 9 | 全部修复 |
| MEDIUM | 15 | 全部修复 |
| LOW | 10 | 评估后保留/已修复 |

---

## CRITICAL 修复

### C-1: sync_service.py Shell注入回归 (CRITICAL)
- **文件**: `server/application/services/sync_service.py`
- **修复**: 对rsync命令所有动态参数添加 `shlex.quote()` — source_path, target_path, username, domain, key file path
- **附带修复**: sshpass密码通过 `env={"SSHPASS": password}` 传递给子进程；`__import__("datetime")` 替换为正常import

### C-2: agent.py exec端点RCE无防护 (CRITICAL)
- **文件**: `server/api/agent.py`
- **修复**: 添加 `DANGEROUS_PATTERNS` 危险命令正则检测 + 403拦截；API Key比较改为 `secrets.compare_digest()`；`proc.kill()` 后加 `await proc.wait()` 防僵尸进程；server_id 类型验证

### C-3: WebSSH IDOR — token未绑定server_id (CRITICAL)
- **文件**: `server/api/webssh.py`
- **修复**: 验证JWT token中的server_id与路径参数匹配，不匹配返回4003关闭连接

---

## HIGH 修复

### H-1: PUT/POST端点setattr任意字段注入 (HIGH)
- **文件**: `servers.py`, `settings.py`, `assets.py`, `scripts.py`
- **修复**: 为每个模型定义字段白名单 (SERVER_CREATE_FIELDS, SCHEDULE_CREATE_FIELDS, PLATFORM_CREATE_FIELDS, SCRIPT_CREATE_FIELDS, CREDENTIAL_CREATE_FIELDS等)；create端点用 `safe_data = {k:v for k,v in payload.items() if k in WHITELIST}` 过滤；update端点只set白名单内字段

### H-2: settings/assets/scripts端点无JWT认证 (HIGH)
- **文件**: `settings.py`, `assets.py`, `scripts.py`
- **修复**: 所有端点添加 `admin: Admin = Depends(get_current_admin)` 依赖

### H-3: refresh_token并发重放攻击 (HIGH)
- **文件**: `server/application/services/auth_service.py`
- **修复**: refresh时先清空旧token (invalidate-then-generate模式)，并发请求第二个会因找不到token而失败

### H-4: servers.py N+1 Redis查询 (HIGH)
- **文件**: `server/api/servers.py`
- **修复**: 使用Redis pipeline批量获取所有heartbeat key，单次round-trip

### H-5: agent.py proc.kill()僵尸进程 (HIGH) — 与C-2合并修复

### H-6: agent.py heartbeat server_id类型验证 (MEDIUM→HIGH) — 与C-2合并修复

### H-7: settings API Key/Secret泄露 (HIGH)
- **文件**: `server/api/settings.py`
- **修复**: 定义 `SENSITIVE_SETTING_KEYS` 集合；list/get返回 `***MASKED***`；PUT禁止修改secret_key/encryption_key

### H-8: TOTP暴力破解无速率限制 (HIGH)
- **文件**: `server/application/services/auth_service.py`
- **修复**: 添加内存TOTP速率限制器，5次失败后锁定5分钟

### H-9: get_optional_admin独立session泄漏 (HIGH)
- **文件**: `server/api/auth_jwt.py`
- **修复**: 改用 `_get_request_session(request)` 获取request-scoped session

---

## MEDIUM 修复

### M-2: X-Forwarded-For IP伪造
- **文件**: `server/api/auth.py`
- **修复**: 优先使用X-Real-IP（Nginx设置）；X-Forwarded-For取最后一个值（Nginx追加）

### M-3: asyncssh known_hosts=None — 添加ADR注释说明
- **文件**: `server/infrastructure/ssh/asyncssh_pool.py`
- **修复**: 添加ADR-012注释说明跳过原因（受控服务器环境）

### M-4: asyncssh异常信息泄露服务器地址
- **文件**: `server/infrastructure/ssh/asyncssh_pool.py`
- **修复**: ConnectionError只包含server_id，完整错误写入logger；exec_ssh_command返回通用错误消息

### M-5: 分页limit无上限
- **文件**: `settings.py`, `assets.py`
- **修复**: audit_logs limit上限500；ssh_sessions上限200；command_logs上限500；retry_jobs上限500

### M-9: API层直接import infrastructure层
- **文件**: `servers.py`, `agent.py`
- **修复**: 在 `dependencies.py` 添加 `get_redis_client()` 抽象函数，API层通过此函数获取Redis客户端

### M-10: WebSocket ConnectionManager单进程限制
- **文件**: `server/api/websocket.py`
- **修复**: 添加 `global_client_count()` 方法，通过Redis聚合多worker连接数

### M-11: servers.py Redis overlay逻辑重复
- **文件**: `server/api/servers.py`
- **修复**: 提取 `_overlay_redis_heartbeat()` 辅助函数，list_servers和get_server共用

### M-13: login_attempts表缺少查询索引
- **文件**: `server/domain/models/__init__.py`
- **修复**: 添加 `Index('idx_login_attempts_check', 'username', 'ip_address', 'success', 'attempted_at')`

### M-14: sync_service批量获取server逐个查询
- **文件**: `server/domain/repositories/__init__.py`, `server/infrastructure/database/server_repo.py`, `server/application/services/sync_service.py`
- **修复**: ServerRepository添加 `get_by_ids(ids)` 方法，使用 `IN` 查询一次获取所有server

### M-15: API错误消息中英文混用
- **文件**: 所有API路由文件
- **修复**: 统一为中文错误消息（服务器未找到、平台未找到、脚本未找到、必填等）

---

## 修改文件清单

1. `server/api/servers.py` — setattr白名单+JWT auth+Redis pipeline+overlay去重+中文错误消息
2. `server/api/settings.py` — setattr白名单+JWT auth+敏感设置掩码+分页上限+中文错误消息
3. `server/api/assets.py` — setattr白名单+JWT auth+分页上限+中文错误消息
4. `server/api/scripts.py` — setattr白名单+JWT auth+中文错误消息
5. `server/api/agent.py` — 危险命令检测+compare_digest+僵尸进程+server_id验证+Redis抽象+中文错误消息
6. `server/api/webssh.py` — IDOR server_id绑定
7. `server/api/auth.py` — X-Real-IP优先+X-Forwarded-For取最后一个值
8. `server/api/auth_jwt.py` — get_optional_admin使用request session
9. `server/application/services/sync_service.py` — shlex.quote+sshpass env+__import__替换+批量get_by_ids
10. `server/application/services/auth_service.py` — refresh_token防重放+TOTP速率限制
11. `server/infrastructure/ssh/asyncssh_pool.py` — 错误信息脱敏+ADR注释
12. `server/infrastructure/ssh/pool.py` — exec_command支持env参数
13. `server/infrastructure/database/server_repo.py` — 添加get_by_ids批量查询
14. `server/domain/repositories/__init__.py` — ServerRepository协议添加get_by_ids
15. `server/domain/models/__init__.py` — LoginAttempt添加复合索引
16. `server/api/dependencies.py` — 添加get_redis_client抽象
17. `server/api/websocket.py` — 添加global_client_count多worker支持
18. `server/application/services/sync_engine_v2.py` — sysctl命令注入防护+SFTP错误脱敏
19. `server/application/services/script_service.py` — SSRF私有IP拦截+str(e)脱敏+MYSQL_PWD环境变量
20. `server/api/health.py` — 未认证端点拆分为/health(公开)+/health/detail(需JWT)
21. `server/infrastructure/database/push_schedule_repo.py` — **kwargs setattr改为字段白名单
22. `server/infrastructure/database/sync_log_repo.py` — **kwargs setattr改为字段白名单
23. `server/api/agent.py` — Exception str(e)脱敏
24. `server/background/self_monitor.py` — Telegram消息str(e)脱敏
25. `server/api/webssh.py` — SSH连接/Shell创建错误str(e)脱敏+关闭原因不暴露server_id
26. `server/application/services/sync_service.py` — error_message脱敏+stderr不写入DB
27. `server/infrastructure/database/ssh_session_repo.py` — __import__替换为正常import
28. `server/api/sync_v2.py` — 错误消息统一中文
29. `server/api/servers.py` — _server_to_dict移除username字段(防SSH凭据泄露)
30. `server/infrastructure/ssh/pool.py` — ValueError不暴露host地址
31. `server/infrastructure/database/server_repo.py` — import语句移至文件顶部
