Files
hms/docs/audits/v2/05-security-performance.md
iven df1d85bfde docs: T40 UI 审计报告 + wiki 更新 + Docker 配置
- T40 UI 审计计划和结果文档(docs/qa/)
- wiki 更新:miniprogram 设计系统合规审计记录 + index 关键数字更新
- 审计 V2 完整报告(docs/audits/v2/)
- 讨论记录文档(docs/discussions/)
- 设计规格和实施计划(docs/superpowers/)
- 角色测试计划和结果(docs/qa/role-test-*)
- Docker 生产部署配置
2026-05-13 23:29:42 +08:00

128 lines
4.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# V2 审计 — 安全合规与性能审计
> 日期: 2026-05-04
## 一、安全审计
### S1: SQL 注入防护 — 存在高危漏洞
| 编号 | 严重度 | 问题 | 位置 |
|------|--------|------|------|
| **SEC-01** | **高** | `patient_id`/`user_id` 通过 `format!` 拼接进 SQL | `action_inbox_service.rs:272-306` |
| SEC-01a | 低 | 迁移种子 SQL 使用 `format!` | 迁移文件(硬编码 UUID风险极低 |
| -- | 安全 | `erp-plugin` 动态表操作 | `sanitize_identifier()` 40+ 处调用,覆盖完整 |
**SEC-01 详情**:
```rust
// action_inbox_service.rs 第 272-306 行
let patient_filter = match &query.patient_id {
Some(pid) => format!("AND patient_id = '{}'", pid), // 直接拼接!
None => String::new(),
};
let assigned_filter = format!("AND f.assigned_to = '{}'", user_id.unwrap()); // 直接拼接!
```
`tenant_id` 已正确使用 `$1` 参数化,但 `patient_id``user_id` 未参数化。虽然来源是已认证用户的上下文(非直接用户输入),但仍违反安全规范。
**修复**: 改为 `Statement::from_sql_and_values` 参数化绑定。
### S2: PII 加密覆盖 — 合规
AES-256-GCM + 随机 nonce + v1 前缀 + Zeroizing 密钥。
| Entity | 加密字段 |
|--------|---------|
| patient | id_number, phone, address, emergency_contact, emergency_phone |
| family_member | phone |
| doctor_profile | license_number |
| consultation_message | content |
| follow_up_record | result, plan, medication_notes |
| diagnosis | note, value |
| lab_report | report_content, conclusion |
| medication_record | note, value |
**结论**: 所有 PII 字段均已加密。解密使用 `unwrap_or` 降级兼容旧数据。
### S3: API Key 安全 (BLE 网关) — 合格
- 存储: SHA-256 哈希 + 前 8 位前缀双因子
- 生成: `OsRng` 32 字节随机密钥
- 传输: `Authorization: Gateway <key>``X-Gateway-Key`
- **不足**: 代码层未强制 HTTPS需在反向代理层配置 TLS
### S4: OAuth 安全 — 部分合规
| 检查项 | 状态 |
|--------|------|
| scope 验证 | 合规 — 白名单校验 |
| client_secret 存储 | 合规 — Argon2 哈希 |
| 速率限制 | 已建模,未强制执行 |
| PKCE | 不支持(仅 Client Credentials |
| redirect_uri | 不适用 |
### S5: 多租户隔离 — 合规(有一处增强建议)
- 应用层: 所有 handler 带 `ctx.tenant_id` 过滤
- 数据库层: PostgreSQL RLS 在所有含 tenant_id 表上启用
- SSE: 验证 `event.tenant_id != tenant_id` 跳过非本租户事件
- **不足**: FHIR `allowed_patient_ids` 在 JWT claims 中携带但未在查询层强制执行
### S6: 权限码一致性 — 存在缺失
| 编号 | 严重度 | 问题 |
|------|--------|------|
| **SEC-02** | **中** | OAuth 管理 handler5 个端点)未调用 `require_permission()` |
所有其他 53 个 PermissionDescriptor 声明的权限码均有对应 `require_permission` 调用。
### S7: XSS 防护 — 合规
Web 和 MP 中均未发现 `dangerouslySetInnerHTML``innerHTML` 使用。
### S8: SSE 认证 — 合规
- AI SSE: JSON POST + `TenantContext` + `require_permission`
- 消息 SSE: JWT `?token=xxx` query param 回退 + tenant_id 验证
## 二、性能审计
### P1: N+1 查询 — 低风险
未发现典型 N+1 模式。告警引擎 `for rule in rules` 循环中有额外 DB 查询,但规则数量通常个位数。
### P2: 分页覆盖率 — 高
- 使用 `PaginationParams` 的 handler: 11 个文件
- 自定义分页: alert, action_inbox, patient
- 无分页: doctors, devices, tags, categories, consents, rules, templates, thresholds通常数据量小
### P3: AI 缓存 — 未启用
`AnalysisService::find_cached()` 方法存在但仅用于测试。生产流程未调用。`ai_usage.is_cache_hit` 字段已预留。
| 编号 | 严重度 | 问题 |
|------|--------|------|
| **PERF-01** | **中** | AI 分析缓存功能存在但未启用 |
### P4: 索引覆盖率 — 合规
最近 19 个迁移新增 22 个索引,覆盖所有新表。所有新表均含 `tenant_id` 索引。
### P5: 批量操作 — 高效
- 设备数据: `insert_many` + `ON CONFLICT DO NOTHING`
- 随访: `batch_create/assign/complete`
- 插件: `batch_delete/update` 使用 `IN (...)`
## 三、问题汇总
| 编号 | 严重度 | 类型 | 问题 | 位置 |
|------|--------|------|------|------|
| SEC-01 | **高** | 注入 | SQL `format!` 拼接 patient_id/user_id | action_inbox_service.rs:272-306 |
| SEC-02 | **中** | 权限 | OAuth handler 缺少 require_permission | oauth/handler.rs (5 端点) |
| SEC-03 | **中** | 越权 | FHIR allowed_patient_ids 未在查询层执行 | fhir/handler.rs |
| SEC-04 | **低** | 配置 | JWT secret dev fallback 硬编码 | oauth/middleware.rs:67 |
| SEC-05 | **低** | 限流 | rate_limit_per_minute 已建模未执行 | oauth/service.rs |
| PERF-01 | **中** | 缓存 | AI 分析缓存未启用 | erp-ai/service/analysis.rs |
| PERF-02 | **低** | 分页 | 部分列表端点缺分页 | 各 handler |