fix(security): implement all 15 security fixes from penetration test V1

Security audit (2026-03-31): 5 HIGH + 10 MEDIUM issues, all fixed.

HIGH:
- H1: JWT password_version mechanism (pwv in Claims, middleware verification,
  auto-increment on password change)
- H2: Docker saas port bound to 127.0.0.1
- H3: TOTP encryption key decoupled from JWT secret (production bailout)
- H4+H5: Tauri CSP hardened (removed unsafe-inline, restricted connect-src)

MEDIUM:
- M1: Persistent rate limiting (PostgreSQL rate_limit_events table)
- M2: Account lockout (5 failures -> 15min lock)
- M3: RFC 5322 email validation with regex
- M4: Device registration typed struct with length limits
- M5: Provider URL validation on create/update (SSRF prevention)
- M6: Legacy TOTP secret migration (fixed nonce -> random nonce)
- M7: Legacy frontend crypto migration (static salt -> random salt)
- M8+M9: Admin frontend: removed JS token storage, HttpOnly cookie only
- M10: Pipeline debug log sanitization (keys only, 100-char truncation)

Also: fixed CLAUDE.md Section 12 (was corrupted), added title.rs middleware
skeleton, fixed RegisterDeviceRequest visibility.
This commit is contained in:
iven
2026-04-01 08:38:37 +08:00
parent 3b1a017761
commit e3b93ff96d
26 changed files with 597 additions and 220 deletions

View File

@@ -0,0 +1,125 @@
# ZCLAW 安全渗透测试报告 V1.0
> 审计日期: 2026-03-31
> 审计范围: zclaw-saas 后端、desktop Tauri 应用、admin-v2 管理面板
> 审计方法: 白盒代码审计 + 灰盒攻击面分析
> 整体评级: **B+** (良好)
---
## 一、执行摘要
对 ZCLAW 项目三大子系统进行了全面安全审计,覆盖 12 个安全领域、80+ API 端点、~80 个 Tauri IPC 命令。
**核心结论**: 未发现 Critical 级漏洞。项目安全架构设计良好Argon2id、参数化 SQL、AES-256-GCM、RBAC但在 JWT 生命周期管理、CSP 策略、密钥隔离方面存在改进空间。
共发现 **5 项 HIGH** + **10 项 MEDIUM** + **7 项 LOW** 级问题全部已修复HIGH + MEDIUM或记录LOW
---
## 二、已修复漏洞清单
### HIGH 级 (5 项 — 全部已修复)
| # | 漏洞 | 影响 | 修复方案 |
|---|------|------|----------|
| H1 | 密码修改后 JWT 不失效 | 攻击者窃取 JWT 后密码修改仍可使用 24h | `password_version` 机制: JWT claims 加入 pwv中间件比对 DB 值,密码修改时递增 |
| H2 | Docker SaaS 端口绑定所有接口 | 生产环境 SaaS 直接暴露公网 | 改为 `127.0.0.1` 绑定,仅通过 nginx 反代访问 |
| H3 | TOTP 加密密钥与 JWT 密钥耦合 | JWT 泄露 → 所有加密数据同时泄露 | 生产环境强制独立 `ZCLAW_TOTP_ENCRYPTION_KEY`,缺失时拒绝启动 |
| H4 | Tauri CSP `connect-src http://*` | XSS 后可向任意 HTTP 端点外泄数据 | 收紧为 `http://localhost:* https://*` |
| H5 | Tauri CSP `unsafe-inline` 脚本 | 允许内联脚本执行,削弱 XSS 防护 | 移除 `script-src 'unsafe-inline'` |
### MEDIUM 级 (10 项 — 全部已修复)
| # | 漏洞 | 修复方案 |
|---|------|----------|
| M1 | 限流仅内存存储 | PostgreSQL `rate_limit_events` 表持久化 |
| M2 | 无账户锁定机制 | 5 次失败锁定 15 分钟DB 字段追踪 |
| M3 | 弱邮箱验证 | RFC 5322 regex + 254 字符长度限制 |
| M4 | 设备注册无输入约束 | typed struct + 字段长度限制 |
| M5 | Provider URL 仅执行时验证 SSRF | 创建/更新时即验证 URL拒绝私有 IP |
| M6 | Legacy 固定 Nonce TOTP 加密 | 启动时自动迁移到随机 Nonce 格式 |
| M7 | Legacy 静态 Salt 前端加密 | v1→v2 自动迁移,随机 salt |
| M8 | Token 存储 JS 内存 | 移除 Zustand 中的 token 字段,仅用 HttpOnly Cookie |
| M9 | Refresh Token 重复传递 Header | 移除 Authorization Bearer 回退 |
| M10 | Pipeline 日志含用户数据 | 截断到 100 字符,敏感值替换为 [REDACTED] |
---
## 三、已确认安全区域
| 领域 | 评级 | 证据 |
|------|------|------|
| **SQL 注入** | 安全 | 全量参数化查询 (sqlx `.bind()`),无字符串拼接 |
| **命令注入** | 安全 | `Command::new` 不用 shell参数均为编译时常量 |
| **路径遍历** | 安全 | 文件操作用硬编码路径pipeline_id 严格过滤 |
| **密码存储** | 安全 | Argon2id + OsRng 随机盐 + spawn_blocking |
| **加密实现** | 安全 | AES-256-GCM + 随机 12 字节 Nonce |
| **错误泄露** | 安全 | 内部错误统一返回 "服务内部错误" |
| **JWT 基础** | 安全 | audience 验证、JTI 唯一、refresh 单次 rotation |
| **RBAC** | 安全 | 自我角色提升阻断、Token 权限范围限制 |
| **SSRF** | 安全 | 全面的 URL 验证 (私有 IP/DNS/混淆) |
| **CORS** | 安全 | 生产强制白名单,缺失拒绝启动 |
| **Cookie** | 安全 | HttpOnly + Secure + SameSite=Strict |
| **XFF** | 安全 | 仅信任配置代理 IP |
---
## 四、涉及修改的文件
### 数据库迁移 (新增)
- `migrations/20260401000004_accounts_password_version.sql`
- `migrations/20260401000005_rate_limit_events.sql`
### Rust 后端 (修改)
- `crates/zclaw-saas/src/auth/jwt.rs` — Claims pwv 字段
- `crates/zclaw-saas/src/auth/handlers.rs` — 登录锁定 + 邮箱验证 + pwv
- `crates/zclaw-saas/src/auth/mod.rs` — 中间件 pwv 验证
- `crates/zclaw-saas/src/config.rs` — TOTP 密钥强制独立
- `crates/zclaw-saas/src/state.rs` — AppCache 字段
- `crates/zclaw-saas/src/lib.rs` — cache 模块注册
- `crates/zclaw-saas/src/models/account.rs` — AccountLoginRow 字段
- `crates/zclaw-saas/src/cache.rs` — 已存在,注册到 lib
- `crates/zclaw-saas/src/crypto.rs` — Legacy TOTP 迁移函数
- `crates/zclaw-saas/src/main.rs` — 调用迁移
- `crates/zclaw-saas/src/middleware.rs` — 持久化限流
- `crates/zclaw-saas/src/account/handlers.rs` — 设备注册约束
- `crates/zclaw-saas/src/model_config/handlers.rs` — Provider URL 验证
- `crates/zclaw-pipeline/src/executor.rs` — 日志脱敏
- `crates/zclaw-pipeline/src/actions/mod.rs` — 日志脱敏
### 前端 (修改)
- `desktop/src-tauri/tauri.conf.json` — CSP 加固
- `desktop/src/lib/crypto-utils.ts` — Legacy 加密迁移
- `admin-v2/src/stores/authStore.ts` — 移除 token 存储
- `admin-v2/src/services/request.ts` — 移除 Bearer header
- `admin-v2/src/router/AuthGuard.tsx` — isAuthenticated 检查
- `admin-v2/src/pages/Login.tsx` — login 调用更新
### 配置 (修改)
- `docker-compose.yml` — 端口绑定 + env_file
---
## 五、验证结果
| 检查项 | 结果 |
|--------|------|
| `cargo check -p zclaw-saas` | ✅ 通过 |
| `cargo test -p zclaw-saas --lib` | ✅ 17/17 通过 |
| `npx tsc --noEmit` (admin-v2) | ✅ 零错误 |
| 安全扫描 | 建议: `cargo audit` + `pnpm audit` + `trivy` |
---
## 六、LOW 级监控项 (暂不修复)
| # | 项目 | 说明 |
|---|------|------|
| L1 | Dev JWT fallback 密钥 | `#[cfg(debug_assertions)]` 保护 |
| L2 | Demo API Key 种子数据 | 显然假值 |
| L3 | 浏览器自动化 eval | 设计如此 |
| L4 | 自定义 Markdown 渲染器 | 已用 DOMPurify 缓解 |
| L5 | Console 日志引用 Token | 不记录值 |
| L6 | format!() 用于表名 | 编译时常量 |
| L7 | docker-compose env_file 引用示例 | 文档说明即可 |