DESIGN.md@backend_safety/docs · git:20260617.47f66a5 · 2026-06-17 · sha256 e801c77be98ef483
DESIGN.md@backend_safety/docs git:20260617.47f66a5A
Immutable. This exact content never changes and is served at /api/v1/blob/e801c77be98ef483.
# 架构设计文档
> backend_safety — 高性能安全底层引擎(Rust)
---
## 一、项目目标与性能指标
| 模块 | 目标 | 指标 |
| ---------- | ---------------------- | ----------------------------------- |
| 二进制解析 | 流式解析 GB 级文件 | 峰值内存 < 128 MB(与文件大小无关) |
| 二进制解析 | MP4/MKV 解析吞吐 | ≥ 500 MB/s(NVMe 本地磁盘) |
| 加密 | ChaCha20-Poly1305 吞吐 | ≥ 1 GB/s(单线程) |
| 加密 | Argon2id 密钥派生 | 300–500 ms(可调,防暴力破解) |
| 私钥操作 | secp256k1 签名 | ≥ 10,000 签名/s |
| 私钥存储 | 密钥写入/读取 | 无明文落盘,OS Keychain 隔离 |
---
## 二、模块设计
### 2.1 大文件二进制解析 (`src/parser/`)
**核心问题**:Python/Go 解析 GB 级二进制文件时,通常需要将全文件载入内存,导致 OOM;且 GC 语言的字节操作性能远低于 Rust。
**方案:零拷贝流式解析 + Rayon 并行**
```
磁盘文件
│
▼
BufReader(mmap 或 O_DIRECT,chunk_size = 64KB)
│
▼
FormatDetector(魔数识别:MP4/MKV/ZIP/PDF/ELF...)
│
▼
FormatParser(nom 解析器组合子,零拷贝引用原始 buffer)
│ 解析 atom/box/chunk
▼
SchemaBuilder(结构化元数据 + 感兴趣数据段偏移量)
│
├──▶ 流式 gRPC 响应(ParseChunk stream)
└──▶ 元数据摘要(FileMetadata)
```
**关键设计决策**:
- 使用 `nom` 解析器组合子框架——声明式描述二进制格式,无需手写状态机
- 解析器操作 `&[u8]` 切片引用,不复制数据(零拷贝)
- 大文件通过 `memmap2` 做内存映射,OS 负责分页,用户态永远只持有窗口引用
- `Rayon` 线程池并行解析独立数据块(如视频的多个 track)
- 恶意格式保护:所有 `nom` 解析器设置深度/长度上限,防止 parser bomb(zip bomb / 嵌套攻击)
- 解析器通过 `cargo-fuzz` 模糊测试,覆盖畸形输入场景
**支持格式(可扩展)**:
| 格式 | 用途 |
| ------------ | -------------------------------- |
| MP4 / MOV | 视频元数据、track 信息、时间轴 |
| MKV / WebM | Matroska 容器解析 |
| ZIP / gzip | 压缩包目录结构,不解压提取元数据 |
| PDF | 对象流、XRef table、元数据 |
| ELF | 二进制可执行文件分析 |
| 自定义二进制 | 通过 schema 描述文件扩展 |
**文件**:
```
src/parser/
├── mod.rs # Parser trait 定义,FormatDetector
├── stream.rs # 流式读取,mmap 封装
├── formats/
│ ├── mp4.rs # ISO Base Media File Format (ISOBMFF)
│ ├── mkv.rs # EBML / Matroska
│ ├── zip.rs # ZIP End of Central Directory
│ └── ...
└── schema.rs # ParseResult, FileMetadata, ParseChunk
```
---
### 2.2 敏感数据加密 (`src/crypto/`)
**核心问题**:Python 的 `cryptography` 库和 Go 的 `crypto/aes` 均依赖 CGO 或 C 扩展;Rust 的 `ring` / `aws-lc-rs` 提供经过 FIPS 验证的纯 Rust 或硬件加速实现,且内存安全由编译器保证。
**方案:信封加密 + 密钥隔离**
```
明文数据
│
▼
[信封加密 Envelope Encryption]
│
├── 1. 生成随机 DEK(Data Encryption Key,256-bit)
│
├── 2. DEK 加密明文:ChaCha20-Poly1305 or AES-256-GCM
│ nonce = random 96-bit(每次加密独立)
│ 密文 = nonce || ciphertext || tag
│
├── 3. DEK 用 KEK(Key Encryption Key)加密
│ KEK 来自 Keystore(不出安全边界)
│
└── 4. 返回:{ encrypted_dek, nonce, ciphertext, aad }
│
▼
DEK 使用完毕立即 zeroize(Zeroize trait)
```
**密钥派生(KDF)**:
```
用户密码/口令
│
▼
Argon2id(memory=64MB, iterations=3, parallelism=4)
│ 防 GPU/ASIC 暴力破解
▼
256-bit 派生密钥(用作 KEK 或直接加密)
```
**关键设计决策**:
- **算法选型**:优先 `ChaCha20-Poly1305`(移动/嵌入式友好,无 padding oracle),备选 `AES-256-GCM`(硬件 AES-NI 场景)
- **Nonce 管理**:每次加密强随机 nonce,96-bit,96-bit nonce 在 2^32 次加密前不重复(NIST SP 800-38D)
- **AAD(Additional Authenticated Data)**:绑定文件 ID / 用户 ID,防止密文被挪用到其他上下文
- **内存安全**:所有密钥/明文变量实现 `Zeroize` trait,离开 scope 时编译器保证清零(防止被 swap 到磁盘或 core dump 泄露)
- **常量时间**:MAC 校验使用 `subtle::ConstantTimeEq`,防止通过响应时间推断 tag 内容
- **禁止使用**:ECB 模式、MD5/SHA-1 作为 MAC、自实现加密算法
**文件**:
```
src/crypto/
├── mod.rs # Crypto trait,算法选择
├── aead.rs # AEAD 加密/解密(ring crate)
├── kdf.rs # Argon2id / PBKDF2(argon2 crate)
├── zeroize.rs # 内存安全擦除辅助类型 SecretBytes
└── envelope.rs # 信封加密组合逻辑
```
---
### 2.3 私钥安全存储 (`src/keystore/`)
**核心问题**:私钥(尤其区块链私钥)一旦泄露不可撤销;普通文件存储、环境变量、数据库字段均有泄露风险(日志、备份、内存 dump)。
**方案:分层存储抽象 + OS 安全飞地**
```
KeystoreVault trait
│
┌───────────────┼───────────────┐
▼ ▼ ▼
OsKeychainBackend EncryptedFile Pkcs11Backend
(macOS Keychain / Backend (HSM / YubiKey)
Linux Keyring) (软件 fallback)
```
**OsKeychainBackend**(推荐):
- macOS:`Security.framework` Keychain,私钥存储在 Secure Enclave(Apple Silicon)
- Linux:`libsecret` / kernel keyring(`KEY_SPEC_SESSION_KEYRING`)
- 密钥通过 `KeyHandle`(随机 UUID)引用,应用层永远不持有明文私钥字节
**EncryptedFileBackend**(开发/无 Keychain 场景):
```
私钥明文
│
▼
Argon2id(master_password) ──▶ KEK
│
▼
AES-256-GCM 加密私钥
│
▼
./storage/keys.vault({ key_id, encrypted_key, nonce, salt }[] })
```
**BIP-39 / BIP-32 支持**:
```
entropy (128~256 bit)
│
├── BIP-39 ──▶ 助记词(12~24 个英文单词)
│ │
│ ▼
└── BIP-32 ──▶ Master Key ──▶ m/44'/60'/0'/0/0(派生路径)
│
▼
以太坊地址 / 公钥
```
**关键设计决策**:
- `KeyHandle` 设计:类似 capability token,仅用于引用密钥,服务重启后失效,需重新认证
- 签名操作在 Keystore 内部完成(`Sign(handle, message) -> Signature`),私钥字节不离开安全边界
- 支持 secp256k1(比特币/以太坊)、ed25519(Solana/Cosmos)、P-256(通用 TLS)
- 密钥导出仅允许公钥导出,私钥导出需要显式授权(二次验证)
- 审计日志:每次签名/访问操作记录到不可篡改日志(append-only,可对接区块链存证)
**文件**:
```
src/keystore/
├── mod.rs # KeystoreVault trait,KeyHandle 类型
├── vault.rs # 组合后端,统一入口
├── os_keychain.rs # macOS / Linux OS 集成
├── encrypted_file.rs # 软件态加密文件存储
├── bip39.rs # 助记词(bip39 crate)
└── bip32.rs # HD 派生(bitcoin crate / k256)
```
---
## 三、跨语言集成
本服务通过 **gRPC** 对外暴露,与 Python(FastAPI)和 Go(高并发引擎)双向集成:
```
┌─────────────────────┐ gRPC / TLS ┌──────────────────────┐
│ Python FastAPI │ ◀────────────────────▶ │ backend_safety │
│ backend/main.py │ │ (Rust, port 9090) │
└─────────────────────┘ └──────────────────────┘
│
┌─────────────────────┐ gRPC / TLS │
│ Go 高并发引擎 │ ◀──────────────────────────────────┘
│ backend_massive_ │ 解析大文件时调用 ParseFile stream
│ concurrent/ │ 加密抓取结果时调用 Encrypt
└─────────────────────┘
```
**gRPC 连接安全**:
- mTLS(双向 TLS),客户端需提供证书,防止未授权调用
- gRPC 拦截器做请求鉴权(JWT / HMAC-SHA256 签名)
---
## 四、技术选型
| 组件 | 选型 | 理由 |
| ------------ | -------------------------------- | ------------------------------ |
| 异步运行时 | `tokio` | 工业级 async,gRPC server 必选 |
| gRPC | `tonic` | Rust 原生,code-gen from proto |
| 二进制解析 | `nom` | 组合子,零拷贝,安全,可 fuzz |
| 内存映射 | `memmap2` | 跨平台 mmap,安全封装 |
| 并行计算 | `rayon` | CPU 密集任务数据并行 |
| 加密 | `ring` / `aws-lc-rs` | FIPS 140-2,经大规模生产验证 |
| Argon2 | `argon2` crate | 官方实现,内存硬化 KDF |
| 内存安全擦除 | `zeroize` | 防编译器优化掉清零操作 |
| 常量时间 | `subtle` | 防时序攻击 |
| BIP-39/32 | `bip39` + `k256` | secp256k1 标准实现 |
| OS Keychain | `keyring` crate | 跨平台 Keychain 抽象 |
| 错误处理 | `thiserror` + `anyhow` | 结构化错误类型 |
| 配置 | `config` crate | TOML / env 分层配置 |
| 日志 | `tracing` + `tracing-subscriber` | 结构化,异步友好 |
| 模糊测试 | `cargo-fuzz` (libFuzzer) | 解析器安全必备 |
| 安全审计 | `cargo-audit` | 自动扫描依赖 CVE |
---
## 五、威胁模型
| 威胁 | 缓解措施 |
| ---------------------------------- | ----------------------------------------------------- |
| 内存读取(core dump / /proc/mem) | `zeroize` 擦除密钥,`mlock` 锁定关键内存页(防 swap) |
| 时序攻击 | `subtle::ConstantTimeEq` 全面替换 `==` 用于安全比较 |
| Parser Bomb(zip bomb / 嵌套攻击) | nom 解析器硬编码深度/长度上限 |
| 私钥文件泄露 | 密钥仅存 OS Keychain,明文永不落盘 |
| 中间人攻击 | gRPC mTLS,证书固定(Certificate Pinning) |
| 依赖供应链攻击 | `cargo audit`,`cargo deny`,lock file 固定版本 |
| 暴力破解密钥派生 | Argon2id(内存硬化),限制 KDF 并发调用次数 |
| Nonce 重用 | 每次加密强随机 nonce,禁止计数器 nonce |
---
## 六、开发计划
### Phase 1 — 基础框架(1周)
- [ ] `Cargo.toml`,workspace 配置
- [ ] `proto/safety.proto` 接口定义
- [ ] `tonic` gRPC server 框架搭建
- [ ] `config` 配置加载,`tracing` 日志
### Phase 2 — 加密模块(1周)
- [ ] `src/crypto/aead.rs`:ChaCha20-Poly1305 + AES-256-GCM
- [ ] `src/crypto/kdf.rs`:Argon2id 密钥派生
- [ ] `src/crypto/zeroize.rs`:SecretBytes 类型
- [ ] `src/crypto/envelope.rs`:信封加密
- [ ] 单元测试 + `cargo-fuzz` 目标
### Phase 3 — 私钥存储(1周)
- [ ] `KeystoreVault` trait 定义
- [ ] `OsKeychainBackend`(macOS 优先)
- [ ] `EncryptedFileBackend`(fallback)
- [ ] BIP-39 助记词,BIP-32 派生路径
- [ ] secp256k1 / ed25519 签名
### Phase 4 — 二进制解析(1.5周)
- [ ] `src/parser/stream.rs`:mmap 流式读取
- [ ] MP4 / ISOBMFF 解析器(nom)
- [ ] ZIP 目录结构解析器
- [ ] 模糊测试覆盖,parser bomb 防护
### Phase 5 — 集成与生产加固(0.5周)
- [ ] gRPC mTLS 配置
- [ ] `cargo-audit` CI 集成
- [ ] Prometheus metrics(`metrics` crate)
- [ ] Docker 镜像(distroless base,最小攻击面)
---
## 七、性能基准
```bash
cargo bench
```
| 基准 | 目标 |
| ------------------------ | -------------------------------- |
| `bench_chacha20_1mb` | ≥ 1 GB/s |
| `bench_argon2id` | 300~500ms(security/speed 权衡) |
| `bench_mp4_parse_1gb` | ≤ 2s,峰值 RSS < 128 MB |
| `bench_sign_secp256k1` | ≥ 10,000 ops/s |
| `bench_encrypt_envelope` | ≥ 100,000 ops/s(不含 KDF) |