# 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语句移至文件顶部