Procházet zdrojové kódy

docs: 新增高危漏洞修复报告

补充核实结论、修复清单与无感加固说明(UTF-8)。

Co-authored-by: Cursor <cursoragent@cursor.com>
吴树波 před 2 dny
rodič
revize
c1600cf798

+ 105 - 0
docs/高危漏洞修复报告-补充-无感加固.md

@@ -0,0 +1,105 @@
+# 补充修复报告:不影响业务逻辑的安全加固
+
+> **筛选原则**:只修复「正常请求路径不变、仅加固防护」的漏洞;不改权限体系、不改鉴权模型、不强制变更业务流程。  
+> **完成时间**:2026-08-06  
+> **编译验证**:`mvn -pl fs-common,fs-framework,fs-service,fs-user-app,fs-company,fs-qw-api,fs-admin,fs-qwhook -am compile -DskipTests` 通过  
+
+---
+
+## 一、本轮筛选结论
+
+| 类型 | 是否本轮修复 | 原因 |
+|------|--------------|------|
+| XXE 禁用 DTD | **已修** | 仅加强 XML 解析器特性,正常企微明文 XML 不受影响 |
+| Runtime.exec → ProcessBuilder | **已修** | 命令参数相同,仅调用方式更安全 |
+| 禁止 html/htm 上传/下载白名单 | **已修** | HIS 业务一般不需要上传可渲染 HTML;可阻断存储型 XSS |
+| 剩余裸 uploadOSS | **已修** | 复用已有白名单工具,合法类型仍可用 |
+| 安全响应头 nosniff | **已修** | 仅增加响应头,不影响业务数据 |
+| 知识库上传文件名清洗 | **已修** | 仅过滤危险字符,中英文名仍可用 |
+| Jackson DefaultTyping 收紧 | **未改** | 可能影响 Redis 历史缓存反序列化,风险大于收益,需单独评估 |
+| 后台补 `@PreAuthorize` | **未改** | 依赖权限点配置,可能造成后台 403 |
+| fs-company-app `/**` permitAll | **未改** | 改动会冲击现有 `@Login` 拦截体系 |
+| 跨租户 companyId 强制覆盖 | **未改** | 可能影响运营超管跨公司操作 |
+
+---
+
+## 二、已修复明细
+
+### 1. XXE(中危-01 等)
+
+| 文件 | 改动 |
+|------|------|
+| 新增 `fs-common/.../XmlSecurityUtils.java` | 统一禁用 DTD/外部实体 |
+| `fs-qw-api/.../QwController.java` | 使用 `XmlSecurityUtils.newSafeDocumentBuilder()` |
+| `fs-service/.../qwApi/util/XMLParse.java` | 补齐与官方安全示例一致的 feature |
+
+**影响**:正常企微回调 XML 无 DOCTYPE,解析结果不变。
+
+### 2. 命令注入(中危-03/04/05)
+
+| 文件 | 改动 |
+|------|------|
+| `HuaweiVodServiceImpl` / `HuaweiObsServiceImpl` | `Runtime.exec(拼接串)` → `ProcessBuilder` 参数数组 |
+| `AudioUtils`(company / qwhook / qwhook-msg / qwhook-sop / fastgptApi) | silk 编码改为 `ProcessBuilder` |
+| `ProcessManager` + `LiveServiceImpl#buildFFmpegCommand` | 改为 `List<String>` 传参,路径不再被空格拆开 |
+
+**影响**:ffmpeg / silk 参数语义不变,路径含空格时反而更稳。
+
+### 3. 存储型 XSS / 上传(中危-07、剩余高危-08)
+
+| 文件 | 改动 |
+|------|------|
+| `MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION` | **移除 `html`/`htm`**(保留 txt/文档/图片/视频/pdf) |
+| `fs-qw-api/.../CommonController#uploadOSS` | 接入 `OssUploadSecurityUtils` |
+| `fs-user-app/.../CommonScrmController#uploadOSS` | 接入 `OssUploadSecurityUtils` |
+
+**影响**:若业务确有上传 `.html` 页面需求会被拒绝;常规图片/文档/音视频不受影响。
+
+### 4. 响应头(低危 nosniff)
+
+| 文件 | 改动 |
+|------|------|
+| `fs-framework/.../SecurityConfig.java` | 增加 `.headers().contentTypeOptions()` |
+
+**影响**:仅增加 `X-Content-Type-Options: nosniff`,不影响接口数据。
+
+### 5. 知识库文件名(中危-10)
+
+| 文件 | 改动 |
+|------|------|
+| `fs-admin` / `fs-company` `ChatDatasetFileController#getFileNameWithoutExtension` | 白名单过滤危险字符,长度限制 50 |
+
+**影响**:含特殊符号的文件名会被清洗,中英文与数字下划线不受影响。
+
+---
+
+## 三、明确跳过(避免影响使用)
+
+1. **Jackson `activateDefaultTyping(LaissezFaire...)`**  
+   全仓库大量 RedisConfig 使用,贸然改为白名单可能导致登录态/缓存读失败。建议单独做兼容验证后再改。
+
+2. **垂直越权补权限注解 / 强制 companyId**  
+   会改变后台可见数据范围或触发 403,需产品与权限表配合。
+
+3. **优惠券竞态加分布式锁**  
+   属逻辑增强,可能改变高并发领取时序,需业务确认。
+
+4. **下载接口去掉客户端 `delete` 参数**  
+   若前端依赖该参数清理临时文件,直接删除会改变行为;建议业务确认后改。
+
+---
+
+## 四、建议回归点(轻量)
+
+1. 企微回调是否正常(XXE 加固后)  
+2. 上传图片/PDF/xlsx/mp4 是否正常;确认 `.html` 被拒绝符合预期  
+3. 语音转 silk / 视频 ffmpeg 合并是否正常  
+4. 直播录播推流(FFmpeg List 传参)是否正常  
+5. 知识库 Excel 导入文件名是否正常显示  
+
+---
+
+## 五、总结
+
+本轮只做了**无感安全加固**:XXE、命令执行方式、html 上传封禁、剩余 OSS 白名单、nosniff、文件名清洗。  
+不涉及鉴权模型、权限点、支付主流程、租户隔离策略,正常业务使用面基本不受影响。

+ 273 - 0
docs/高危漏洞修复报告.md

@@ -0,0 +1,273 @@
+# ylrz_his_scrm_java 高危漏洞核实与修复报告
+
+> **依据文档**:`安全漏洞审计报告.md`  
+> **核实范围**:本地仓库 `ylrz_his_scrm_java`  
+> **修复原则**:仅对已核实存在的高危项做最小安全加固,不改动正常业务主流程;支付/登录/上传等接口在原有逻辑上增加校验或关闭后门  
+> **修复完成时间**:2026-08-06  
+> **编译验证**:`mvn -pl fs-common,fs-framework,fs-service,fs-user-app,fs-company-app,fs-admin -am compile -DskipTests` 通过  
+
+---
+
+## 一、核实结论总览
+
+审计报告列出高危约 **36** 项(含编号重叠)。本地核实结果如下:
+
+| 结论 | 数量 | 说明 |
+|------|------|------|
+| **已确认存在并已修复** | 28 | 见下文「已修复清单」 |
+| **报告描述存在,当前仓库不存在** | 4 | 高危-02/03/07/16 对应文件或接口不在本仓库 |
+| **存在但未做破坏性大改(有说明)** | 4 | 如 fs-company-app 全量 `permitAll`、部分后台垂直越权需配权限位 |
+| **额外发现并已处理** | 1 | 硬编码万能短信验证码后门 |
+
+---
+
+## 二、不存在 / 与报告不一致的项
+
+| 编号 | 报告描述 | 核实结果 |
+|------|----------|----------|
+| 高危-02 | `CrmBusinessMapper.xml` orderBy 注入 | **不存在**:`mapper/crm` 下无 `CrmBusinessMapper.xml` |
+| 高危-03 | `CrmCustomerMapper.xml` `${orderBy}` | **不存在**:该 XML 无 `${orderBy}` / `${maps.orderBy}` 拼接点 |
+| 高危-07 | `CrmExtDetailMapper.xml` 动态 DDL | **不存在**:无该 Mapper 文件 |
+| 高危-16 | `loginByUnionId` 后门 | **不存在**:`AppLoginController` 无此接口(仅有合法微信 code 换取 unionId 流程) |
+| 高危-24 | `getUserInfoByUserId` 无 `@Login` | **当前未发现该接口**(或已移除),不纳入本次改动 |
+| 高危-25/26 | admin 跨公司员工列表 | 与高危-21 同类;本次未做大规模权限重构,避免影响运营后台菜单权限体系,列入后续项 |
+
+---
+
+## 三、已修复清单(按报告编号)
+
+### A. SQL 注入
+
+#### [高危-01] LiveDataMapper `${category}` — **已修复**
+- **核实**:`LiveDataMapper.xml` L142/L192 存在 `SUM(ld.${category})`
+- **修复位置**:
+  - 新增 `fs-common/.../security/SqlSafeUtils.java`(`validateLiveCategory`)
+  - `LiveDataServiceImpl#getTrendData` / `getCompanyTrendData` 入口白名单校验  
+    仅允许:`page_views`、`unique_visitors`、`total_views`、`unique_viewers`、`streams`
+- **业务影响**:非法 category 直接拒绝;合法统计维度不变
+
+#### [高危-04][高危-05] sortOrder 排序注入 — **已修复**
+- **核实**:`FsStoreOrderScrmMapper.xml` / `LiveOrderMapper.xml` 等使用 `${maps.sortOrder}`,且位于 `ORDER BY <字段>` 之后,语义为 asc/desc
+- **修复位置**:
+  - `FsStoreOrderParam`(his / hisStore)自定义 `setSortOrder`
+  - `LiveOrderParam` 自定义 `setSortOrder`
+  - 统一走 `SqlSafeUtils.validateOrderDirection`
+
+#### [高危-06] SortUtils 排序字段名注入 — **已修复**
+- **核实**:`SortUtils.parseSort` 仅校验方向,未校验字段名
+- **修复位置**:`fs-common/.../SortUtils.java`  
+  字段名仅允许 `[a-zA-Z0-9_]+`,方向仅允许 asc/desc
+
+---
+
+### B. 上传 / 路径穿越 / SSRF
+
+#### [高危-08] uploadOSS 无后缀白名单 — **已修复(核心模块)**
+- **新增**:`OssUploadSecurityUtils`(安全后缀白名单,排除 html/jsp 等)
+- **修复文件**:
+  - `fs-company/.../CommonController.java`
+  - `fs-admin/.../CommonController.java`(含 `uploadWang`)
+  - `fs-store/.../CommonController.java`
+  - `fs-company-app/.../CommonController.java`
+  - `fs-user-app/.../CommonController.java`
+  - `fs-doctor-app/.../CommonController.java`
+  - `fs-company/.../ChatUploadController.java`
+- **说明**:其余模块若仍有同类 `uploadOSS` 副本,建议继续复用 `OssUploadSecurityUtils`
+
+#### [高危-09] uploadOSS2 原始文件名路径注入 — **已修复**
+- **修复**:改为 `uploadSuffix` + 白名单,不再用原始文件名构造 OSS key  
+  (`fs-company` CommonController 等)
+
+#### [高危-10] TalentController 路径穿越 + 未鉴权 — **已修复**
+- **修复位置**:`fs-user-app/.../TalentController.java`
+  - 恢复 `@Login`
+  - 后缀白名单
+  - 本地落盘改用 UUID 文件名,并做 canonical path 校验
+
+#### [高危-11] 声纹 URL SSRF — **已修复**
+- **新增**:`UrlSecurityUtils.validatePublicHttpUrl`
+- **修复位置**:
+  - `CompanyUserController#addVoicePrintUrl`
+  - `AudioUtils.audioWAVFromUrl`(`fs-service/.../fastgptApi/util/AudioUtils.java`)
+
+#### [高危-12] FastGpt `urlToFile` SSRF — **已修复**
+- **修复位置**:`FastGptCollectionServiceImpl#urlToFile`  
+  URL 校验 + 临时文件固定 `.tmp` 后缀
+
+#### [高危-13] 视频临时文件后缀可控 — **已修复**
+- **修复位置**:`FsUserVideoServiceImpl#uploadVideo`  
+  仅允许 `.mp4`,临时文件固定 `.tmp`
+
+---
+
+### C. 鉴权与权限
+
+#### [高危-14][高危-15] `loginByUserId` / `loginTest` — **已修复(禁用)**
+- **修复位置**:`AppLoginController`
+- **方式**:保留路径,统一返回 `403 该接口已禁用`,并打 warn 日志  
+  (避免直接删方法导致部分客户端 404 误判;功能上已不可登录)
+
+#### [高危-17] fs-company-app `/**` permitAll — **未改为 Spring Security 强制认证**
+- **原因**:该模块依赖自定义 `@Login` + 拦截器;直接改为 `anyRequest().authenticated()` 会大面积打断现有 JWT 体系,属于逻辑性破坏
+- **本次替代措施**:补齐关键接口 `@Login` / 归属校验(见高危-28/29)
+- **建议**:单独立项做 Spring Security 与拦截器统一
+
+#### [高危-18][高危-19][高危-23] 匿名放行过宽 — **已修复(fs-framework SecurityConfig)**
+- **修复位置**:`fs-framework/.../SecurityConfig.java`
+- **已移除匿名**:
+  - `/common/uploadOSS**`、`/common/uploadWang**`、下载类、`unbindQwUserByServerIds`
+  - `/his/data/*` 系列危险运维接口
+  - Swagger / Druid 匿名
+- **仍保留匿名**:支付回调、短信回调等第三方回调必要路径
+
+#### [高危-20][高危-21][高危-22] 后台大量缺 `@PreAuthorize` — **部分未改**
+- **原因**:补权限注解依赖菜单权限点是否已配置,盲目添加会导致正常后台功能 403
+- **建议**:按菜单权限表分批补齐(P1)
+
+---
+
+### D. 数据越权
+
+#### [高危-28] changeUserInfo / disabled IDOR — **已修复**
+- **修复位置**:`fs-company-app/.../FsUserController.java`
+  - `changeUserInfo`:校验 `fs_user_company_user` 归属当前销售
+  - `changeUserRemark`:校验归属
+  - `disabled` / `enabled`:批量校验归属
+
+#### [高危-29] delMyCard / changeUserState / getUserList — **已修复**
+- **修复位置**:`fs-company-app/.../UserController.java`
+  - `delMyCard`:校验 `card.userId == 当前用户`
+  - `changeUserState`:管理员 + 同公司校验
+  - `getUserList`:补 `@Login`
+
+---
+
+### E. 逻辑漏洞
+
+#### [高危-30] 微信支付 switch fall-through — **已修复**
+- **修复位置**:`WxPayController#wxPayNotify`  
+  每个 case 增加 `break`,并增加 `default` 日志  
+- **说明**:注释已标明该接口不可用、应走 `/store/app/wxpay/wxPayNotify`;本次仍修复,防止误调用造成重复入账
+
+#### [高危-31] 汇付回调未验签 — **已修复**
+- **修复位置**:`PayScrmController#hfPayNotify`  
+  使用 `JsonUtils.sort4JsonString` + `RsaUtils.verify` + `BasePay.HUIFU_DEFAULT_PUBLIC_KEY` 先验签,失败返回 `fail`
+
+#### [高危-32] 短信验证码可复用 / 可爆破 — **已修复**
+- **修复位置**:`AppLoginController`
+  - `resetPassword`:失败计数 ≥5 锁定 30 分钟;成功后删除验证码
+  - `loginByPhone` / `registerByPhone`:成功后删除验证码
+
+#### [高危-33] 默认密码 zm12345678 — **当前仓库未命中**
+- 未检索到 `zm12345678` / `getUserDefaultPassword` 自动设密逻辑;无需改动
+
+#### [高危-34] 跨租户重置密码 — **已修复**
+- **修复位置**:`SysUserController#resetPwd`  
+  增加 `userService.checkUserDataScope(user.getUserId())`
+
+---
+
+### F. 反序列化与凭据
+
+#### [高危-35] Fastjson AutoType — **已修复**
+- **修复**:全仓库 **27** 个 `FastJson2JsonRedisSerializer.java`  
+  `setAutoTypeSupport(true)` → `false`
+
+#### [高危-36] 硬编码腾讯云 AK/SK — **已修复**
+- **修复位置**:`SmsTServiceImpl`
+  - 改为 `@Value("${tencent.cloud.secret-id/secret-key}")`
+  - `fs-admin/.../application.yml` 增加环境变量注入占位
+- **运维必做**:
+  1. **立即在腾讯云控制台禁用并轮换**旧密钥 `AKIDdAdvzoQpzuOo...`
+  2. 各环境设置:
+     - `TENCENT_CLOUD_SECRET_ID`
+     - `TENCENT_CLOUD_SECRET_KEY`
+  3. 未配置时短信发送会返回明确错误,避免静默使用硬编码密钥
+
+---
+
+## 四、额外发现并处理
+
+| 项 | 说明 | 处理 |
+|----|------|------|
+| 硬编码万能短信验证码 | `AppLoginController` 原 `INTERNAL_LOGIN_CODE = "EdisonX!@#.+-123"`,可绕过短信登录任意用户 | 已清空禁用;仅当配置非空内部码时才可能生效(当前为空) |
+
+---
+
+## 五、新增公共安全组件
+
+| 类 | 路径 | 作用 |
+|----|------|------|
+| `SqlSafeUtils` | `fs-common/.../security/SqlSafeUtils.java` | 排序方向 / 列名 / live category 白名单 |
+| `UrlSecurityUtils` | `fs-common/.../security/UrlSecurityUtils.java` | SSRF:协议白名单 + 拒绝内网地址 |
+| `OssUploadSecurityUtils` | `fs-common/.../security/OssUploadSecurityUtils.java` | OSS 上传后缀白名单 + 文件名穿越过滤 |
+
+---
+
+## 六、隐患与后续建议(请确认)
+
+1. **腾讯云旧密钥必须轮换**:源码历史中已暴露,仅改代码不够。  
+2. **汇付验签公钥**:当前使用 `BasePay.HUIFU_DEFAULT_PUBLIC_KEY`;若商户使用自定义公钥,需改为按商户配置取公钥,否则合法回调可能验签失败。  
+3. **fs-company-app `/**` permitAll**:仍依赖方法级 `@Login`,遗漏注解即裸奔;建议后续统一鉴权。  
+4. **后台垂直越权(QwUser / CompanyUser / IpadAllocation)**:未批量加 `@PreAuthorize`,避免权限点未配置导致生产不可用;建议按权限表分批治理。  
+5. **其他模块 uploadOSS 副本**:已修核心 6 端 + Chat 上传;ad/qw 等模块若仍有裸上传,可继续复用 `OssUploadSecurityUtils`。  
+6. **关闭 AutoType**:若历史 Redis 缓存依赖 `@type` 多态反序列化,升级后偶发反序列化失败,需观察并清理旧缓存。  
+7. **SecurityConfig 取消 Swagger/Druid 匿名**:开发环境如需调试,可用 profile 单独放开,勿在生产匿名。
+
+---
+
+## 七、修复文件索引(主要)
+
+```
+fs-common/src/main/java/com/fs/common/utils/security/SqlSafeUtils.java          (新增)
+fs-common/src/main/java/com/fs/common/utils/security/UrlSecurityUtils.java       (新增)
+fs-common/src/main/java/com/fs/common/utils/security/OssUploadSecurityUtils.java (新增)
+fs-common/src/main/java/com/fs/common/utils/SortUtils.java
+fs-service/.../live/service/impl/LiveDataServiceImpl.java
+fs-service/.../hisStore/param/FsStoreOrderParam.java
+fs-service/.../his/param/FsStoreOrderParam.java
+fs-service/.../live/param/LiveOrderParam.java
+fs-service/.../course/service/impl/FsUserVideoServiceImpl.java
+fs-service/.../fastGpt/service/impl/FastGptCollectionServiceImpl.java
+fs-service/.../fastgptApi/util/AudioUtils.java
+fs-service/.../sms/service/impl/SmsTServiceImpl.java
+fs-user-app/.../AppLoginController.java
+fs-user-app/.../WxPayController.java
+fs-user-app/.../store/PayScrmController.java
+fs-user-app/.../TalentController.java
+fs-user-app/.../CommonController.java
+fs-company-app/.../CommonController.java
+fs-company-app/.../CompanyUserController.java
+fs-company-app/.../FsUserController.java
+fs-company-app/.../UserController.java
+fs-company/.../common/CommonController.java
+fs-company/.../chat/ChatUploadController.java
+fs-admin/.../common/CommonController.java
+fs-admin/.../system/SysUserController.java
+fs-admin/src/main/resources/application.yml
+fs-store/.../common/CommonController.java
+fs-doctor-app/.../CommonController.java
+fs-framework/.../SecurityConfig.java
+fs-*/.../FastJson2JsonRedisSerializer.java  (27 处)
+```
+
+---
+
+## 八、总结
+
+本次已对审计报告中**本地可核实的高危漏洞**完成加固,覆盖:
+
+- SQL 注入(category / sortOrder / 排序字段)
+- 上传白名单与路径穿越
+- SSRF
+- 登录后门禁用 + 万能验证码禁用
+- 支付 fall-through / 汇付验签
+- 短信验证码一次性与爆破限制
+- Fastjson AutoType
+- 云密钥去硬编码
+- 关键 IDOR 归属校验
+- 管理端危险匿名接口收敛
+
+**未做或需后续立项**的项主要是:CRM 报告中不存在的 Mapper、后台大面积 `@PreAuthorize` 补齐、fs-company-app Spring Security 体系重构。  
+
+部署前请务必完成:**腾讯云密钥轮换**、**各环境注入新密钥**、**汇付回调验签联调**、**上传白名单业务抽样回归**。