docs: 审计整改清单 + P0 完成(track 前后端)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
liuyun 2026-10-11 16:11:11 +08:00
parent 0e257d444d
commit 72a35c189e
3 changed files with 65 additions and 2 deletions

63
docs/audit-checklist.md Normal file
View File

@ -0,0 +1,63 @@
# 脚手架审计整改清单
> 状态标记:`⬜ 待处理` · `🔶 需讨论` · `✅ 已决定` · `✔ 已完成`
> 顺序按批次(P0 安全堵漏 → P1 RBAC 闭环 → P2 会话加固 → P3 工程化契约)推进,序号即处理顺序,可调。
## P0 安全越权堵漏
- [x] **C1** 跨租户越权 —— Tenant 表无租户过滤,任意租户超管可管全平台租户。✔ 已完成:`super_admin`=平台超管(保留)、`tenant_super_admin`=租户顶层(保留),`tenant:*` 仅平台租户可授予(constants.ts + roles.service 保留码校验 + 平台级权限剥离)
- [x] **H1** 软删与唯一约束冲突 —— 删后无法重建同名 → P2002 → 500。✔ 已完成:方案 B(BaseCrudService.softRemove 改名回收 `#id`,按列长截断)+ P2002→409
- [x] **H2** 删除角色不清理关联与缓存 —— user_role/role_resource/role_org 残留,聚合不校验已删角色。✔ 已完成:removeRole 级联清理 + 清缓存 + 保留角色禁删 + resolveAuth 过滤已删角色
- [x] **H3** 权限聚合缺 status 过滤 —— 停用资源仍被授权。✔ 已完成:resolveAuth 资源查询补 `status='enabled'`
- [x] **H4** 用户停用/删除后旧 token 仍可用 —— 守卫不查用户状态,缓存 TTL=7 天。✔ 已完成:方案 A(tokenVersion)+ JwtAuthGuard 每请求校验 + Redis 用户状态缓存
- [x] **H5** 重置密码不吊销会话 —— refresh token 不撤销。✔ 已完成:并入 H4,resetPassword/停用/删除 → invalidateSessions(tokenVersion++ + 删 refresh + 清缓存)
- [x] **H6** 角色资源树半选回显导致权限放大 —— 半选父节点被持久化 + 回显级联全选。✔ 已完成:只保存叶子键 `getCheckedKeys(true)` + 回显 `setCheckedKeys(assigned, true)`
- [x] **H10** 401 自动刷新无限循环 —— login/refresh 自身 401 也进刷新重放。✔ 已完成:`_retry` 标记 + 排除 login/refresh + 失败 reject
- [x] **H11** data_scope self 语义错误 —— self 等同本部门;详情接口无数据权限。✔ 已完成:self 按 userId 过滤 + 详情 assertCanView 403
- [x] **H13** seed 幂等副作用 —— 重跑重置管理员密码/启用账号。✔ 已完成:update 分支剥离 password/status
- [x] **M1** 日志脱敏不含 phone/email —— 违反 spec 安全红线。✔ 已完成:mask.ts 补充 phone/mobile/email
- [x] **M6** JWT 密钥默认兜底值 —— 生产忘配置即可伪造 token。✔ 已完成:缺失/生产弱密钥直接拒绝启动
- [x] **M8** pageSize 无上限 —— 可拉全表。✔ 已完成:`@Max(200)`
- [x] **M9** DTO 枚举缺校验 —— status 裸 `@IsString`。✔ 已完成:全 DTO 加 `@IsIn`(UserStatus/CommonStatus/DataScope/ResourceType)
- [x] **M10** Prisma 错误未映射 —— P2002/P2025 原文泄漏且 500。✔ 已完成:P2002→409、P2025→404、未知异常不泄漏内部细节
- [x] **M11** assignResources 非事务 + 不校验 + :id 语义混淆 —— ✔ 已完成:事务化 + 角色存在性校验(:id 实为 roleCode,已注释说明)
- [x] **M22** super_admin 可被租户自建 —— ✔ 已完成:并入 C1,`RESERVED_ROLE_CODES` 校验(super_admin / tenant_super_admin)
- [x] **M4** 组织树可成环 —— collectDescendants 死循环。✔ 已完成:create/update 防环校验 + collectDescendants visited 集合
## P1 RBAC 闭环
- [ ] **H7** 用户-角色分配缺失 —— 无端点/DTO/UI。方案:加分配端点 + DTO + 前端 UI(最高优先)
- [ ] **H9** 按钮级权限未实现 —— 无下发接口/指令,导出按钮不存在。方案:权限码下发 + `v-permission` + 补导出
- [ ] **M18** 前端无路由级权限过滤 + 403 页 —— 方案:路由守卫按权限码过滤 + 403 兜底页
- [ ] **M21** 数据权限覆盖面过窄 —— 仅用户列表。方案:扩展至角色/组织/日志等域
- [ ] **H8** 注册/忘记密码是假功能 —— mock 假成功。方案:补真实后端闭环
- [ ] **M17** 租户 onboarding 断裂 —— 新建租户不可用、删除留孤儿。方案:建租户初始化管理员+根组织+资源/字典模板
- [ ] **新增** 用户自助修改密码/个人资料 —— 缺失清单。方案:补端点 + 前端个人中心
## P2 会话与安全加固
- [ ] **M5** 登录安全基线缺失 —— 无锁定/后端验证码/密码策略。方案:先锁定+密码策略,验证码后置
- [ ] **M7** Swagger 无鉴权 + CORS 全开 + 无 helmet/限流 —— 方案:/docs 收口 + CORS 白名单 + helmet + 限流
- [ ] **M12** RefreshToken 哈希未校验 + 无清理 —— 方案:校验 hash + 过期清理任务
- [ ] **M14** 401 强退后 authStore 失真 —— 方案:handler 里同步重置 authStore
- [ ] **M15** dictStore loaded 守卫无法刷新 —— 方案:fetch 加 force 参数
- [ ] **M20** 登录租户写死 touyun —— 方案:恢复可配置租户输入框(🔶 需讨论,见 D5)
- [ ] **M3** created_by 全项目零写入 —— 方案:BaseCrudService.create 注入 created_by
- [ ] **L5** 登出审计 username 写 null —— 方案:写入真实 username
- [ ] **L7** useRequest loading 竞态 + ty-crud 重复请求 —— 方案:请求序号/去重
- [ ] **L8** 审计/登录日志、refresh_token 无清理任务 —— 方案:定时清理任务
## P3 工程化契约
- [ ] **H12** e2e 必然失败 + 无业务测试 —— 方案:修 e2e + 补核心链路用例
- [ ] **M2** 时间字段 ISO vs Unix 毫秒 —— 方案:API 层转 Unix 毫秒(🔶 需讨论,见 D4)
- [ ] **M16** vite `olldownOptions` 拼写错误 —— 方案:改 `rolldownOptions`
- [ ] **M19** 前端 .env/.env.dev 入库 + .env.example 带像真密码 —— 方案:gitignore + 模板脱敏
- [ ] **L1** 模板残留/无 LICENSE/stats.html 入库 —— 方案:清理 + 补 LICENSE
- [ ] **L2** 启动 console.log 噪音 —— 方案:移除
- [ ] **L3** docs/requirements 空目录 + config/menu.ts 死代码 —— 方案:清理
- [ ] **L4** README 克隆命令与子模块风格不一致 —— 方案:统一
- [ ] **L6** ty-crud 取消确认 rejection 未捕获 —— 方案:catch
- [ ] **L9** @nestjs/mau 非常规依赖 —— 方案:核实来源/用途
- [ ] **L10** 无 CI/Dockerfile/compose 部署编排 —— 方案:补 CI + 部署物料
- [ ] **新增** spec 覆盖补全 —— users/roles/orgs/tenants/configs 与前端多页无 spec 锚点。方案:补主 spec

@ -1 +1 @@
Subproject commit 23e228783cff43f59157e3b8975a57d11cda315d
Subproject commit 7ae220581a3c60c3bb71e2872a721333cbd75288

@ -1 +1 @@
Subproject commit 73ed067a82a52dce7ecad1be30d7f4e1be88092b
Subproject commit 513688a5e6e0387bb00a464d1ec7bdd7e2f6c594