文档权限:冻结R2A三角色权限设计与审计文档
This commit is contained in:
1 parent
82da706006
commit
35832f2fce
9 files changed
+1243
No files matched your search
@@ -0,0 +1,137 @@
|
||||
# RailwaySystem 数据范围与 IDOR 安全防护设计 (Data Scope & IDOR Prevention)
|
||||
|
||||
- **设计版本**: R.2A Design Freeze
|
||||
- **设计日期**: 2026-09-15
|
||||
- **核心目标**: 建立从安全凭证(`SecurityContext`)到业务主体 ID 的单向信任推导链条,杜绝前端参数篡改越权,消除全站直接对象引用(IDOR)安全漏洞。
|
||||
|
||||
---
|
||||
|
||||
## 1. 数据范围核心设计原则 (Zero-Trust Frontend)
|
||||
|
||||
在多角色(Admin, Teacher, Student)登录体系中,数据范围安全必须建立在**零信任前端参数**的基石之上:
|
||||
|
||||
```
|
||||
+─────────────────────────────────────────────────────────────────────────────+
|
||||
| 零信任推导核心防线 (Secure Chain) |
|
||||
| |
|
||||
| 客户端 HTTP Request |
|
||||
| │ (仅携带 Bearer JWT Token,禁止/忽略 query 或 body 中的 identityId) |
|
||||
| ▼ |
|
||||
| Spring Security Filter: JwtAuthenticationTokenFilter |
|
||||
| │ (验签并提取 claims 中的 userId) |
|
||||
| ▼ |
|
||||
| SecurityContextHolder.getContext().getAuthentication() |
|
||||
| │ (获取受信任的 LoginUser.getUserId()) |
|
||||
| ▼ |
|
||||
| Service 内部数据推导 (SecurityContextHelper) |
|
||||
| ├─ 若拥有 train_teacher 角色: |
|
||||
| │ SELECT t_id FROM train_teacher WHERE user_id = #{userId} |
|
||||
| ├─ 若拥有 train_student 角色: |
|
||||
| │ SELECT s_id FROM train_student WHERE user_id = #{userId} |
|
||||
| └─ 若拥有 admin / train_admin 角色: |
|
||||
| 按管理员角色规则放行或基于组织机构过滤 |
|
||||
+─────────────────────────────────────────────────────────────────────────────+
|
||||
```
|
||||
|
||||
### 1.1 核心铁律
|
||||
1. **禁止直接接收外部身份 ID**: 在教师和学员的私有业务接口中,接口方法参数严禁声明 `@RequestParam String studentId` 或 `@PathVariable String teacherId`。
|
||||
2. **强制服务端单向解析**: 所有业务查询条件中的 `studentId`、`teacherId` 必须统一在 Service 事务内由 `SecurityUtils.getUserId()` 动态查询或注入。
|
||||
3. **严格归属校验 (Ownership Assertion)**: 在涉及具体资源主键操作(如查看某个具体 `reportId`、`checkinId`、`enrollmentId`)时,SQL 中必须强制拼接 `AND student_id = #{currentStudentId}` 或 `AND teacher_id = #{currentTeacherId}`,不满足条件时直接返回 `404 Not Found` 或 `403 Forbidden`,坚决不泄露数据存在性。
|
||||
|
||||
---
|
||||
|
||||
## 2. 教师 (Teacher) 业务数据范围推导链条
|
||||
|
||||
教师登录后,其可访问的所有教学资源必须严格基于其受聘授课关系动态推导:
|
||||
|
||||
```
|
||||
┌──────────────────────┐
|
||||
│ sys_user (userId) │
|
||||
└──────────┬───────────┘
|
||||
│ WHERE user_id = #{userId}
|
||||
▼
|
||||
┌──────────────────────┐
|
||||
│ train_teacher (t_id)│
|
||||
└──────────┬───────────┘
|
||||
│
|
||||
┌───────────────────────┼────────────────────────┐
|
||||
│ (排课直接授课) │ (计划课程关联) │ (关联教学班级)
|
||||
▼ ▼ ▼
|
||||
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
|
||||
│timetable_lesson │ │train_plan_course │ │ train_class_plan │
|
||||
│WHERE teacher_id │ │WHERE teacher_id │ │ WHERE plan_id IN │
|
||||
│ = #{t_id} │ │ = #{t_id} │ │ (授课班级集合) │
|
||||
└────────┬─────────┘ └──────────────────┘ └────────┬─────────┘
|
||||
│ │
|
||||
▼ ▼
|
||||
┌──────────────────┐ ┌──────────────────┐
|
||||
│student_checkin │ │training_enrollment
|
||||
│(本人课次考勤流水) │ │(我带的班级学员名单)│
|
||||
└──────────────────┘ └──────────────────┘
|
||||
```
|
||||
|
||||
- **授课课表数据**: 仅能查到 `train_timetable_lesson.teacher_id = #{currentTeacherId}` 的课次。
|
||||
- **关联班级数据**: 仅能查到由当前教师担任授课任务的 `plan_id` 集合。
|
||||
- **班级学员名单**: 仅能读取自己任教班级名单,**严禁读取全校其他培训班的学员档案**,且读取名单时必须对身份证号、住址等个人隐私字段进行脱敏(仅显示后四位)。
|
||||
|
||||
---
|
||||
|
||||
## 3. 学员 (Student) 私有数据范围推导链条
|
||||
|
||||
学员登录后,进入极简个人培训中心,数据范围完全收敛于“本人”:
|
||||
|
||||
```
|
||||
┌──────────────────────┐
|
||||
│ sys_user (userId) │
|
||||
└──────────┬───────────┘
|
||||
│ WHERE user_id = #{userId}
|
||||
▼
|
||||
┌──────────────────────┐
|
||||
│ train_student (s_id)│
|
||||
└──────────┬───────────┘
|
||||
│
|
||||
┌─────────────┬───────────────┼───────────────┬─────────────┐
|
||||
▼ ▼ ▼ ▼ ▼
|
||||
┌───────┐ ┌──────────────┐ ┌───────────┐ ┌──────────────┐ ┌────────────┐
|
||||
│ 个人 │ │ 参训班级名单 │ │ 个人报到 │ │ 个人考勤记录 │ │ 个人画像/ │
|
||||
│ 档案 │ │ Enrollment │ │ Report │ │ Checkin │ │ 学时累计 │
|
||||
│(只读) │ │WHERE s_id=...│ │WHERE s_id │ │WHERE s_id=...│ │WHERE s_id │
|
||||
└───────┘ └──────┬───────┘ └───────────┘ └──────────────┘ └────────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────┐
|
||||
│ 班级参训课表 │
|
||||
│(仅限正常在训)│
|
||||
└──────────────┘
|
||||
```
|
||||
|
||||
- **学员档案**: 仅能读取与更新本人通讯电话、邮箱。
|
||||
- **学员课表**: 仅能读取本人已分班入班(且状态为待报到、已报到或已完成)的班级课次,严禁获取其他班级的教学日程。
|
||||
- **考勤与报到**: 报到记录、打卡记录、学时累计与学员画像全部以 `student_id = #{currentStudentId}` 为严格物理隔离边界。
|
||||
|
||||
---
|
||||
|
||||
## 4. 全站 IDOR 漏洞排查与加固矩阵 (IDOR_RISK_MATRIX)
|
||||
|
||||
本矩阵针对现有 Controller 方法进行逐一安全排查,明确其在多角色模式下的越权风险等级与防护要求:
|
||||
|
||||
| 序号 | 业务接口端点 | 当前实现机制 | 越权风险评定 | 潜在越权利用场景 | R.2 加固与防护措施 |
|
||||
| :---: | :--- | :--- | :---: | :--- | :--- |
|
||||
| 01 | `GET /train/student/{sId}` | 直接根据路径参数 `sId` 查询并返回档案明细 | **AT_RISK (高危)** | 学员登录后篡改 `sId` 抓取全校任意职工身份证号与家庭隐私 | **管理端专有**:普通学员严禁访问此端点;学员本人查阅统一走 `/train/me/student` |
|
||||
| 02 | `GET /train/teacher/{tId}` | 直接根据路径参数 `tId` 查询教师档案 | **AT_RISK (中危)** | 任意登录人员枚举读取全校师资档案 | **管理端专有**;教师本人查阅统一走 `/train/me/teacher` |
|
||||
| 03 | `GET /train/plans/{planId}/timetable` | 直接根据 `planId` 查询整班课次 | **AT_RISK (高危)** | 未参训学员或未授课教师随意侦测其他班级排课安排 | 校验当前登录人是否在该计划的教师或学员名单内,否则直接拒止 |
|
||||
| 04 | `GET /train/plans/{planId}/enrollments` | 直接根据 `planId` 查询全班学员名册 | **AT_RISK (高危)** | 普通学员篡改 `planId` 窃取其他班级全部学员花名册及电话 | **严禁学员访问**;教师仅能查阅所带班级名册且敏感字段脱敏 |
|
||||
| 05 | `GET /train/enrollments/{enrollmentId}` | 直接根据主键 `enrollmentId` 查询 | **AT_RISK (中危)** | 水平越权读取其他学员入班凭证 | 增加 `student_id = currentStudentId` 强行归属校验 |
|
||||
| 06 | `POST /train/attendance/sign-in` | Body 接收 `studentId`, `lessonId` | **AT_RISK (高危)** | 学员 A 抓包伪造请求体中的 `studentId`,为旷课学员 B 代签 | 接口服务端强制断言 `body.studentId == currentStudentId`,否则拦截 |
|
||||
| 07 | `PUT /train/attendance/{checkinId}` | 接收 `checkinId` 与修改状态 | **AT_RISK (高危)** | 普通学员或无关人员抓包篡改他人考勤记录 | 仅限拥有 `train:attendance:edit` 的管理员或授权教师操作 |
|
||||
| 08 | `GET /train/checkin/{checkinId}` | 直接按 ID 查询单条打卡记录 | **AT_RISK (低危)** | 水平遍历探测其他人员打卡位置与时间 | 增加当前登录人身份归属断言 |
|
||||
| 09 | `GET /train/portrait/{portraitId}` | 直接按画像 ID 返回综合能力雷达 | **AT_RISK (高危)** | 学员枚举读取其他学员测评与能力短板数据 | 学员查阅统一走 `/train/me/portrait`,底层绑定本人 ID |
|
||||
| 10 | `GET /train/duration/{durId}` | 直接按主键读取学时记录 | **AT_RISK (中危)** | 水平越权探测他人学时与上线情况 | 学员统一走 `/train/me/duration`,强制本人绑定 |
|
||||
| 11 | `POST /train/plans` (新增计划) | `@PreAuthorize` 鉴权 | `SAFE` | 非管理员无权限直接返回 403 | 角色与菜单隔离即可防御 |
|
||||
| 12 | `POST /train/plans/{id}/lessons` (排课) | `@PreAuthorize` 鉴权 | `SAFE` | 非教务人员无排课权限 | 角色与功能权限隔离即可防御 |
|
||||
|
||||
### 4.1 审计总结
|
||||
- **高危越权端点统计**: `IDOR_RISK_COUNT = 8`。
|
||||
- **防护治理策略**:
|
||||
1. **管理接口封闭**: 原有 `/train/student/**`、`/train/teacher/**`、`/train/enrollments/**` 仅保留给 `train_admin`。
|
||||
2. **自服务通道独立**: 为 Teacher 与 Student 开辟全新的 `/train/me/**` API,彻底切断直接对象引用漏洞源。
|
||||
Reference in new issue
Block a user