- T40 UI 审计计划和结果文档(docs/qa/) - wiki 更新:miniprogram 设计系统合规审计记录 + index 关键数字更新 - 审计 V2 完整报告(docs/audits/v2/) - 讨论记录文档(docs/discussions/) - 设计规格和实施计划(docs/superpowers/) - 角色测试计划和结果(docs/qa/role-test-*) - Docker 生产部署配置
4.9 KiB
4.9 KiB
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 详情:
// 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 位前缀双因子
- 生成:
OsRng32 字节随机密钥 - 传输:
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 管理 handler(5 个端点)未调用 require_permission() |
所有其他 53 个 PermissionDescriptor 声明的权限码均有对应 require_permission 调用。
S7: XSS 防护 — 合规
Web 和 MP 中均未发现 dangerouslySetInnerHTML 或 innerHTML 使用。
S8: SSE 认证 — 合规
- AI SSE: JSON POST +
TenantContext+require_permission - 消息 SSE: JWT
?token=xxxquery 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 |