- middleware.md: 集成契约+3不变量+执行流 (157→136行) - saas.md: 移除安全重复→引用security.md+Token Pool算法 (231→173行) - security.md: 吸收saas认证内容成为安全唯一真相源 (158→199行) - memory.md: 最大压缩363→147行+Hermes洞察提炼+4不变量 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
200 lines
7.2 KiB
Markdown
200 lines
7.2 KiB
Markdown
---
|
||
title: 安全体系
|
||
updated: 2026-04-22
|
||
status: active
|
||
tags: [module, security, auth, encryption]
|
||
---
|
||
|
||
# 安全体系
|
||
|
||
> 从 [[index]] 导航。关联模块: [[saas]] [[routing]] [[middleware]]
|
||
|
||
## 设计决策
|
||
|
||
**核心原则: 多层防御,深度安全。**
|
||
|
||
| 决策 | 为什么 |
|
||
|------|--------|
|
||
| JWT + HttpOnly Cookie 双通道 | Tauri 桌面端用 OS keyring 存 JWT,浏览器用 HttpOnly Cookie 防 XSS 窃取,双环境统一认证 |
|
||
| password_version (pwv) 失效 | 修改密码后自动使所有已签发 JWT 失效,无需 token 黑名单,O(1) 验证 |
|
||
| TOTP AES-256-GCM 加密 | TOTP 共享密钥不能明文存储,随机 Nonce 防重放,生产环境强制独立密钥 |
|
||
| IP 级限流 + 持久化 | 防暴力破解(login 5/min)、防刷注册(3/hour),持久化到 PostgreSQL 避免重启丢失 |
|
||
| CORS 白名单强制 | 生产环境 `cors_origins` 缺失直接拒绝启动,不允许 `*` 通配 |
|
||
|
||
完整审计报告: `docs/features/SECURITY_PENETRATION_TEST_V1.md`
|
||
|
||
## 关键文件 + 数据流
|
||
|
||
### 核心文件
|
||
|
||
| 文件 | 职责 |
|
||
|------|------|
|
||
| `crates/zclaw-saas/src/auth/handlers.rs` | 认证端点: 登录/注册/刷新/TOTP/密码修改 |
|
||
| `crates/zclaw-saas/src/auth/totp.rs` | TOTP 2FA: QR 生成 + 验证 + AES-256-GCM 加密 |
|
||
| `crates/zclaw-saas/src/middleware.rs` | HTTP 中间件栈 (10 层): 认证/限流/配额/CORS |
|
||
| `crates/zclaw-saas/src/relay/key_pool.rs` | Token Pool: Key 加密存储 + RPM/TPM 轮换 |
|
||
| `desktop/src-tauri/src/secure_storage.rs` | OS Keyring: Win DPAPI / macOS Keychain / Linux Secret |
|
||
| `desktop/src-tauri/src/memory/crypto.rs` | 本地记忆加密: AES-256-GCM (可选) |
|
||
|
||
### 认证数据流
|
||
|
||
```
|
||
用户登录 (POST /api/v1/auth/login)
|
||
→ Argon2id + OsRng 验证密码
|
||
→ 账户锁定检查 (5 次失败 → 15 分钟锁定)
|
||
→ 签发 JWT (Claims: user_id, role, pwv)
|
||
→ set_auth_cookies():
|
||
zclaw_access_token (path:/api, 2h TTL, HttpOnly)
|
||
zclaw_refresh_token (path:/api/v1/auth, 7d TTL, HttpOnly)
|
||
Secure: dev=false, prod=true | SameSite=Strict
|
||
|
||
前端存储:
|
||
→ Tauri: OS keyring → saasStore.token
|
||
→ 浏览器: HttpOnly Cookie (JS 不可读)
|
||
→ localStorage: 仅 saasUrl + account 非敏感信息
|
||
```
|
||
|
||
### 集成契约
|
||
|
||
| 方向 | 接口 | 说明 |
|
||
|------|------|------|
|
||
| Provides --> saas | auth_middleware, JWT validation, rate limiting | 每个 API 请求经过认证层 |
|
||
| Provides --> desktop | secure_storage, crypto_utils | 配置/凭据安全存储 |
|
||
| Provides --> admin | admin_guard_middleware | Admin 路由权限验证 |
|
||
|
||
### Auth API 接口
|
||
|
||
**公开路由:**
|
||
|
||
| 方法 | 路径 | 说明 |
|
||
|------|------|------|
|
||
| POST | `/api/v1/auth/register` | 注册 (邮箱 RFC 5322 + 254 字符) |
|
||
| POST | `/api/v1/auth/login` | 登录 (5 次/分钟 IP 限流) |
|
||
| POST | `/api/v1/auth/refresh` | Token 刷新 (单次使用, 旧 token 撤销) |
|
||
| POST | `/api/v1/auth/logout` | 登出 |
|
||
|
||
**受保护路由:**
|
||
|
||
| 方法 | 路径 | 说明 |
|
||
|------|------|------|
|
||
| GET | `/api/v1/auth/me` | 当前用户信息 |
|
||
| PUT | `/api/v1/auth/password` | 修改密码 (触发 pwv 失效) |
|
||
| POST | `/api/v1/auth/totp/setup` | TOTP 设置 (生成 QR) |
|
||
| POST | `/api/v1/auth/totp/verify` | TOTP 验证激活 |
|
||
| POST | `/api/v1/auth/totp/disable` | TOTP 禁用 (需密码) |
|
||
|
||
**Tauri 安全命令:**
|
||
|
||
| 命令 | 说明 |
|
||
|------|------|
|
||
| `secure_store_set` | OS Keyring 存储 |
|
||
| `secure_store_get` | OS Keyring 读取 |
|
||
| `secure_store_delete` | OS Keyring 删除 |
|
||
| `secure_store_is_available` | Keyring 可用性检测 |
|
||
|
||
## 代码逻辑
|
||
|
||
### JWT Password Version 失效机制
|
||
|
||
```
|
||
JWT Claims 含 pwv (password_version) 字段
|
||
→ auth_middleware 每次验证 JWT 时: Claims.pwv vs DB.pwv
|
||
→ 不匹配 → 401 Unauthorized
|
||
→ 修改密码 → DB.pwv 递增 → 所有旧 JWT 自动失效
|
||
→ 无需 token 黑名单,验证成本 O(1)
|
||
```
|
||
|
||
### 密码存储: Argon2id + OsRng
|
||
|
||
```
|
||
注册/修改密码:
|
||
→ OsRng 生成随机盐
|
||
→ Argon2id 哈希 (内存硬 + 时间成本)
|
||
→ 存储到 users.password_hash
|
||
验证:
|
||
→ Argon2id::verify(password, stored_hash)
|
||
→ 失败计数递增 → 5 次后锁定 15 分钟
|
||
```
|
||
|
||
### TOTP / API Key 加密: AES-256-GCM
|
||
|
||
```
|
||
TOTP 密钥存储:
|
||
→ 随机生成 12 字节 Nonce
|
||
→ AES-256-GCM 加密 (密钥: ZCLAW_TOTP_ENCRYPTION_KEY, 64 hex)
|
||
→ 存储 nonce + ciphertext
|
||
解密:
|
||
→ 取出 nonce → AES-256-GCM 解密
|
||
→ 解密失败: warn + 跳过 (不阻塞认证)
|
||
|
||
Provider API Key 同理: heal_provider_keys() 启动时重新加密有效 Key
|
||
```
|
||
|
||
### Token 刷新轮换
|
||
|
||
```
|
||
POST /api/v1/auth/refresh
|
||
→ 验证 refresh_token 有效性
|
||
→ 检查旧 token 是否已撤销 (rotation 防重放)
|
||
→ 撤销旧 refresh_token (写入 DB revoked_at)
|
||
→ 签发新 access_token (2h) + refresh_token (7d)
|
||
```
|
||
|
||
### 限流规则
|
||
|
||
| 端点 | 限制 | 持久化 |
|
||
|------|------|--------|
|
||
| `/api/auth/login` | 5 次/分钟/IP | PostgreSQL |
|
||
| `/api/auth/register` | 3 次/小时/IP | PostgreSQL |
|
||
| 公共端点 | 20 次/分钟/IP | 内存 |
|
||
|
||
### SaaS HTTP 中间件栈 (10 层)
|
||
|
||
| # | 中间件 | 路由组 | 功能 |
|
||
|---|--------|--------|------|
|
||
| 1 | public_rate_limit | Public | IP 限流 |
|
||
| 2 | auth_middleware | Protected+Relay | JWT/Cookie/API Token 身份验证 |
|
||
| 3 | rate_limit_middleware | Protected+Relay | 账户级频率限制 |
|
||
| 4 | quota_check_middleware | Relay | 月度配额检查 |
|
||
| 5 | request_id_middleware | All | UUID 请求追踪 |
|
||
| 6 | api_version_middleware | All | API 版本头 |
|
||
| 7 | TimeoutLayer (15s) | Protected | 非流式请求超时 |
|
||
| 8 | admin_guard | Admin 子路由 | admin 权限验证 |
|
||
| G1 | TraceLayer | All | HTTP 请求追踪 |
|
||
| G2 | CorsLayer | All | CORS 白名单 |
|
||
|
||
## 活跃问题 + 陷阱
|
||
|
||
| 问题 | 级别 | 说明 |
|
||
|------|------|------|
|
||
| CSP 已加固 | Done | Tauri 移除 `unsafe-inline` script,`connect-src` 限制 `http://localhost:*` + `https://*` |
|
||
| TLS 依赖反向代理 | 长期 | Axum 不负责 TLS,nginx/caddy 提供 HTTPS 终止 |
|
||
| Cookie Secure 开发环境 false | 设计意图 | 开发环境 HTTP 无 Secure,生产必须 true |
|
||
|
||
陷阱:
|
||
- JWT 签名密钥: `#[cfg(debug_assertions)]` 有 fallback,release 模式直接 `bail` 拒绝启动
|
||
- TOTP 加密密钥: 生产必须独立设置 `ZCLAW_TOTP_ENCRYPTION_KEY`,不从 JWT 密钥派生
|
||
- CORS 白名单: 生产缺失拒绝启动,不允许通配符
|
||
- Refresh Token: 单次使用,logout 时撤销到 DB,rotation 校验已撤销的旧 token
|
||
|
||
## 变更日志
|
||
|
||
| 日期 | 变更 | 提交 |
|
||
|------|------|------|
|
||
| 2026-04-21 | 移除数据脱敏中间件 (稳定化约束) | fa5ab4e |
|
||
| 2026-04-17 | E2E 测试安全链路验证通过 | — |
|
||
| 2026-04-16 | Agent 隔离修复 + Admin 权限校验 | — |
|
||
| 2026-04-13 | 安全渗透测试 V1: 15 项修复 | — |
|
||
| 2026-04-09 | CSP 加固 + JWT pwv + 账户锁定 + TOTP 解耦 | — |
|
||
|
||
### 测试覆盖
|
||
|
||
| 功能 | 测试文件 |
|
||
|------|---------|
|
||
| 认证流程 | `crates/zclaw-saas/tests/auth_test.rs` |
|
||
| 认证安全边界 | `crates/zclaw-saas/tests/auth_security_test.rs` |
|
||
| 账户安全 | `crates/zclaw-saas/tests/account_security_test.rs` |
|
||
| 权限矩阵 | `crates/zclaw-saas/tests/permission_matrix_test.rs` |
|
||
| TOTP | `crates/zclaw-saas/src/auth/totp.rs` inline tests |
|
||
| 本地加密 | `desktop/src-tauri/src/memory/crypto.rs` inline tests |
|