Files
hzdyjs/问题整改/20261026-安全扫描整改说明.md
T
“wuzhen”andCursor da8d332fac fix(security): 修复网安扫描相关严重/高危/中危漏洞并加固学生密码重置
关闭工作流 SpEL 命令执行与社团活动 SQL 注入,补齐越权、调试接口、登录喷洒和异常回显等问题;学生密码改为随机临时密码,Web/移动端支持复制。

Constraint: 流程发起/办理接口保持仅登录校验,避免影响请假审批
Rejected: 开启验证码 | Web/移动端登录页均未实现,开启会导致无法登录
Confidence: high
Scope-risk: broad
Not-tested: 生产环境与社团社长/指导老师视角
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-26 13:44:51 +08:00

61 lines
5.2 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.
# 2026-10-26 安全扫描整改说明
> 背景:杭州市网安对生产环境进行安全扫描。本次对严重、高危、中危问题做代码级整改;Snail-Job 生产已下线,不在本次范围。
> 后端 `mvn -o compile` 全量通过;前端改动文件无新增类型错误。
## 一、上线前必须执行
| 项 | 说明 |
| --- | --- |
| SQL | `backend/script/sql/update/update_20261026_workflow_permission.sql`:新增工作流管理按钮权限(`workflow:definition:list/edit`、`workflow:instance:manage`、`workflow:task:manage`),并自动授给已拥有「流程定义 / 流程实例 / 待办任务」父菜单的角色。执行后相关用户需**重新登录**。 |
| 配置 | `application.yml` 新增 `security.cors-allowed-origins`(默认放行 `*.hzdyjsxy.cn` 与 localhost),若有其它域名访问后端须补充;`user.password.ipMaxRetryCount: 30`;`sa-token.jwt-secret-key` 已换成随机值。 |
| nginx | 必须向后端传递真实客户端 IP(`X-Forwarded-For` / `X-Real-IP`),否则按 IP 的登录失败锁定失效。 |
## 二、整改清单
### 严重
| 问题 | 整改 |
| --- | --- |
| 工作流 SpEL 表达式注入可执行系统命令(`T(java.lang.Runtime)`) | 新增 `SafeSpelHelper` / `SafeExpressionStrategies`,启动时替换 warm-flow 内置 SpEL 策略:禁止类型引用 `T()`、`new`、反射与 `getClass/forName/exec/getBean` 等方法,仅允许对值类型与 `org.dromara` 业务 Bean 调用 |
| 工作流管理接口无权限控制 | 流程定义全部接口、实例运行/已完成/删除/激活/挂起/变量/作废、全部待办/已办/修改办理人加权限码;`/warm-flow/**` 设计器接口按读写加权限;删除实例、撤销流程要求必须是发起人或具备管理权限 |
| 社团活动列表 SQL 注入 `${params.dataScope}` | Mapper 改为 `#{}` + `foreach` 的类型化参数;Service 先清除请求中 `ds*`/`dataScope` 参数再写入 |
### 高危
| 问题 | 整改 |
| --- | --- |
| 文件 ossId 越权访问 | 学生账号只能访问本人或教职工上传的文件;预签名链接最长 1 小时;异常不回显 |
| 登录喷洒 / 账号枚举 | 账号不存在与密码错误提示一致;同一公网 IP 失败 30 次锁定(内网 IP 不计数) |
| 调试接口暴露 | 删除 `testCoefficient`、`testVicePresidentData`、两个 `debug/permission`、`test/scholarshipTypesStructure`、`debug/sqlLogs`、`test-location`、勤工助学 `debug/{id}` |
| 新生录取名册导出无权限 | 加 `zsjy:enrollment:process:export` 或 `query` |
| 学生考核申请越权、篡改分数 | 学生只能增删改查本人申请;审核字段(教师评分、总分、审核人等)服务端清空;只允许状态 1/2/3 时修改 |
| 应聘越权 | `/apply`、`/my` 强制使用当前登录人;`/submit` 强制状态为 pending |
| 按学号重置学生密码 | 改为随机临时密码并踢下线;学院账号只能操作本学院学生;操作日志不记录响应 |
| 异常信息回显 SQL/堆栈 | `GlobalExceptionHandler.safeMessage` 过滤含 SQL、类名等技术信息的消息;64 处 `R.fail(e.getMessage())` 统一过滤 |
| 出国附件任意类型上传 | 扩展名白名单;Content-Type 按扩展名决定(系统 OSS 上传同步改造),不信任客户端 |
### 中危
| 问题 | 整改 |
| --- | --- |
| SSE 任意用户群发 | 删除 `/resource/sse/send`、`/sendAll`(前端未使用,服务端推送不受影响) |
| CORS 回显任意 Origin 且允许携带凭证 | 仅放行配置的本校域名 |
| 心理咨询预约/爽约限制越权 | 无管理权限时 studentId 强制为本人 |
| 社团报名/签到越权查询 | 无管理权限时 userId/学号强制为本人 |
| 奖学金 `/my` 越权 | 无列表权限时 applicantId 强制为本人 |
| 参数配置读取初始密码 | `configKey` 仅公开白名单键;`sys.user.initPassword` 需用户新增/重置密码权限 |
| 学生信息完善批量赋值 | 状态、来源、创建人始终由服务端设置 |
| 前端存储型 XSS | 新增 `web/src/utils/htmlSafe.ts`;招聘岗位富文本清洗、简历 PDF 字段转义、报修图片预览去掉 innerHTML |
| 开放重定向 | 社交登录回调只允许跳转本校域名;报修附件下载仅重定向 http(s) 地址并安全编码文件名 |
| 日志泄露 | 生产关闭 MyBatis StdOut SQL 日志;登录监听不再打印 token;微信下载不再打印带 access_token 的 URL |
| JWT 默认密钥 | 更换为随机值 |
## 三、遗留与运维事项
1. 默认密码 `Hzdyjsxs123456!@#`、`Hzdyjs123456!@#` 已出现在攻击日志中,需排查并强制修改仍使用默认密码的账号。
2. 轮换 git 历史中出现过的数据库、Redis、监控、CAS 等密钥;确认数据库、Redis、监控端口不对公网开放。
3. 实习日志 `calendar` / `monthly-statistics` 的 studentId 未做归属校验(需权限码,移动端未调用),后续补充。
4. 社团成员 `approvalFlow/{memberId}`、用户导入结果弹窗 `dangerouslyUseHTMLString`(仅管理员)风险较低,后续处理。
5. web 端 `xljk/consultation/calendar/debug.vue` 页面与勤工助学 `debug/statistics` 调用对应的后端接口已不存在,可删除前端代码。