新增贷款定价敏感信息加密设计文档
This commit is contained in:
324
doc/2026-03-30-loan-pricing-sensitive-data-encryption-design.md
Normal file
324
doc/2026-03-30-loan-pricing-sensitive-data-encryption-design.md
Normal file
@@ -0,0 +1,324 @@
|
||||
# 贷款定价流程客户敏感信息加密改造设计文档
|
||||
|
||||
## 1. 背景
|
||||
|
||||
贷款定价流程当前对客户名称 `custName`、证件号码 `idNum` 采用明文传输、明文存储、明文展示的方式处理,不满足客户敏感信息安全要求。
|
||||
|
||||
本次需求已经明确限定为:
|
||||
|
||||
- 仅覆盖贷款定价流程主链
|
||||
- 敏感字段仅包含 `custName`、`idNum`
|
||||
- `custIsn` 不属于本次敏感字段范围
|
||||
- 不改造传输层字段加密
|
||||
- 仅要求存储加密、展示脱敏
|
||||
- 页面不提供任何明文查看入口
|
||||
- 流程查询改为仅允许通过客户内码 `custIsn` 查询
|
||||
- 现有存量数据不迁移,直接清空历史流程数据
|
||||
- 加密密钥从后端配置文件读取,按当前项目最短路径落地
|
||||
|
||||
## 2. 已确认约束
|
||||
|
||||
- 仅修改贷款定价流程相关前后端与数据库脚本,不扩散到系统其他模块
|
||||
- 不覆盖模型输出表的敏感字段治理
|
||||
- 不新增前端字段级加密协议
|
||||
- 不引入外部密钥管理系统
|
||||
- 不新增兼容性字段、补丁式逻辑或降级分支
|
||||
- 必须保证新流程数据落库为密文
|
||||
- 必须保证列表页、详情页始终只展示脱敏值
|
||||
- 必须保证模型调用链路仍能拿到业务所需明文
|
||||
|
||||
## 3. 现状分析
|
||||
|
||||
当前贷款定价流程主链如下:
|
||||
|
||||
1. 前端个人/企业建单弹窗提交明文 `custName`、`idNum`
|
||||
2. 后端 `LoanPricingWorkflowServiceImpl` 通过 `LoanPricingConverter` 将 DTO 转为 `LoanPricingWorkflow`
|
||||
3. `loan_pricing_workflow.cust_name`、`loan_pricing_workflow.id_num` 直接保存明文
|
||||
4. 列表页查询 SQL 直接查询 `lpw.cust_name`
|
||||
5. 详情页接口直接返回流程实体中的 `custName`、`idNum`
|
||||
6. `LoanPricingModelService` 从流程表读取数据后直接组装模型调用 DTO
|
||||
|
||||
现状问题有三类:
|
||||
|
||||
1. 存储层风险:数据库中存在明文客户名称和证件号码
|
||||
2. 展示层风险:前端列表页、详情页直接展示敏感明文
|
||||
3. 查询链路风险:当前列表页仍允许按客户名称查询,与密文存储目标冲突
|
||||
|
||||
## 4. 方案对比
|
||||
|
||||
### 方案一:应用层统一 AES 加解密,返回前统一脱敏
|
||||
|
||||
做法:
|
||||
|
||||
- 在后端新增贷款定价专用敏感字段加解密组件
|
||||
- 创建流程时对 `custName`、`idNum` 加密后再落库
|
||||
- 查询详情、模型调用前在服务内部解密
|
||||
- 返回前端前统一转成脱敏值
|
||||
- 前端仅负责调整查询条件和展示,不做加解密
|
||||
|
||||
优点:
|
||||
|
||||
- 改动集中,符合最短路径实现
|
||||
- 与数据库实现解耦,不绑定数据库方言
|
||||
- 业务边界清晰,易于控制哪些链路允许拿明文
|
||||
- 便于测试和排查
|
||||
|
||||
缺点:
|
||||
|
||||
- 需要明确服务内部解密和对外脱敏的边界,避免遗漏
|
||||
|
||||
### 方案二:MyBatis TypeHandler 自动加解密
|
||||
|
||||
做法:
|
||||
|
||||
- 为实体敏感字段挂载统一的 TypeHandler
|
||||
- 插入自动加密、查询自动解密
|
||||
- 返回前再补充脱敏
|
||||
|
||||
优点:
|
||||
|
||||
- 业务代码表面改动更少
|
||||
|
||||
缺点:
|
||||
|
||||
- 链路不直观,联表 SQL、VO 查询、模型调用等位置容易出现加解密边界不清
|
||||
- 调试复杂度高,不符合本次最短路径目标
|
||||
|
||||
### 方案三:数据库函数处理加解密
|
||||
|
||||
做法:
|
||||
|
||||
- 在 SQL 中直接调用数据库加解密函数
|
||||
- 应用层只负责脱敏
|
||||
|
||||
优点:
|
||||
|
||||
- 应用层代码改动相对少
|
||||
|
||||
缺点:
|
||||
|
||||
- 强依赖数据库能力
|
||||
- 维护成本高
|
||||
- 联表与分页查询复杂度上升
|
||||
- 不符合本次直接、清晰的实现要求
|
||||
|
||||
## 5. 设计结论
|
||||
|
||||
采用方案一:应用层统一 AES 加解密,返回前统一脱敏。
|
||||
|
||||
最终设计原则如下:
|
||||
|
||||
- `loan_pricing_workflow.cust_name`、`loan_pricing_workflow.id_num` 仅保存密文
|
||||
- 服务内部按需短暂解密,仅供业务处理和模型调用使用
|
||||
- 面向前端返回时,`custName`、`idNum` 永远转换为脱敏值
|
||||
- 列表查询去掉客户名称条件,只保留客户内码等非敏感查询项
|
||||
- 存量流程数据通过清空历史数据处理,不做迁移兼容
|
||||
|
||||
## 6. 架构设计
|
||||
|
||||
本次在贷款定价流程模块内新增两类职责:
|
||||
|
||||
### 6.1 敏感字段加解密服务
|
||||
|
||||
新增贷款定价专用组件 `SensitiveFieldCryptoService`,负责:
|
||||
|
||||
- 从后端配置文件读取 AES 密钥
|
||||
- 对 `custName`、`idNum` 执行加密
|
||||
- 对已落库密文执行解密
|
||||
- 在密钥缺失或解密失败时抛出明确异常
|
||||
|
||||
该组件只处理加密和解密,不参与脱敏展示逻辑。
|
||||
|
||||
### 6.2 敏感字段展示服务
|
||||
|
||||
新增贷款定价专用组件 `LoanPricingSensitiveDisplayService`,负责:
|
||||
|
||||
- 对客户名称进行脱敏
|
||||
- 对证件号码进行脱敏
|
||||
- 对流程详情对象和列表对象中的敏感字段做统一替换
|
||||
|
||||
该组件不依赖当前系统管理员免脱敏逻辑,严格执行全员脱敏规则。
|
||||
|
||||
## 7. 数据链路设计
|
||||
|
||||
### 7.1 创建流程链路
|
||||
|
||||
1. 前端建单弹窗提交明文 `custName`、`idNum`
|
||||
2. 后端 DTO 转实体后,在 `createLoanPricing` 入库前统一加密
|
||||
3. `loan_pricing_workflow` 表保存密文
|
||||
4. 创建成功后后续流程继续使用同一主记录
|
||||
|
||||
### 7.2 列表查询链路
|
||||
|
||||
1. 前端列表页移除客户名称搜索项,新增或保留客户内码查询
|
||||
2. 后端分页查询不再按 `custName` 过滤
|
||||
3. 列表 SQL 仍查询 `cust_name` 字段,但查询结果为密文
|
||||
4. 服务返回前将列表 VO 中 `custName` 转为脱敏值
|
||||
5. 前端直接展示后端返回的脱敏结果
|
||||
|
||||
### 7.3 详情查询链路
|
||||
|
||||
1. 后端根据流水号查询流程记录,拿到密文 `custName`、`idNum`
|
||||
2. 服务内部先解密得到业务所需明文
|
||||
3. 若需要组装详情对象或进行后续处理,使用解密后的值
|
||||
4. 返回前调用展示服务,将 `custName`、`idNum` 替换为脱敏值
|
||||
5. 前端详情页只展示脱敏内容
|
||||
|
||||
### 7.4 模型调用链路
|
||||
|
||||
1. `LoanPricingModelService` 根据流程主键读取流程记录
|
||||
2. 读取到的 `custName`、`idNum` 为密文
|
||||
3. 调用模型前先在服务内部解密
|
||||
4. 将解密后的明文复制到 `ModelInvokeDTO`
|
||||
5. 模型调用完成后,模型输出链路保持现状,不纳入本次改造
|
||||
|
||||
## 8. 后端改造设计
|
||||
|
||||
### 8.1 配置项
|
||||
|
||||
后端新增贷款定价敏感字段加密配置项,例如:
|
||||
|
||||
- 是否启用敏感字段加解密
|
||||
- AES 密钥
|
||||
|
||||
本次仅要求配置文件读取固定密钥,不扩展到数据库参数表或外部密钥系统。
|
||||
|
||||
### 8.2 服务层改造
|
||||
|
||||
需要修改以下关键点:
|
||||
|
||||
1. `LoanPricingWorkflowServiceImpl#createLoanPricing`
|
||||
在 `loanPricingWorkflowMapper.insert` 前统一加密 `custName`、`idNum`
|
||||
|
||||
2. `LoanPricingWorkflowServiceImpl#selectLoanPricingBySerialNum`
|
||||
查询详情后先解密,再在返回前脱敏
|
||||
|
||||
3. `LoanPricingWorkflowServiceImpl#selectLoanPricingPage`
|
||||
分页结果中的 `custName` 统一转为脱敏值
|
||||
|
||||
4. `LoanPricingWorkflowServiceImpl#buildQueryWrapper`
|
||||
删除 `custName` 查询条件,改为仅支持 `custIsn`、创建者、机构号等非敏感字段
|
||||
|
||||
5. `LoanPricingModelService#invokeModelAsync`
|
||||
模型调用前解密 `custName`、`idNum`,确保模型收到明文业务数据
|
||||
|
||||
### 8.3 对象边界
|
||||
|
||||
本次不新增明文返回字段,也不保留“密文字段 + 展示字段”双轨结构,避免对象语义膨胀。
|
||||
|
||||
返回前对象中的敏感字段直接替换为脱敏值,确保控制器和前端都不会拿到明文。
|
||||
|
||||
## 9. 前端改造设计
|
||||
|
||||
### 9.1 列表页
|
||||
|
||||
修改 `ruoyi-ui/src/views/loanPricing/workflow/index.vue`:
|
||||
|
||||
- 移除“客户名称”查询项
|
||||
- 改为支持客户内码查询
|
||||
- 表格中 `custName` 继续展示,但其值来自后端脱敏结果
|
||||
|
||||
### 9.2 详情页
|
||||
|
||||
修改个人与企业详情组件:
|
||||
|
||||
- 保持字段布局不变
|
||||
- `custName`、`idNum` 直接展示后端返回的脱敏值
|
||||
- 不新增“查看明文”“复制原值”等交互入口
|
||||
|
||||
### 9.3 建单页
|
||||
|
||||
个人和企业建单弹窗仍然录入明文 `custName`、`idNum`,不新增前端字段加密逻辑。
|
||||
|
||||
## 10. 数据库处理设计
|
||||
|
||||
本次数据库处理遵循最短路径:
|
||||
|
||||
1. 不修改 `loan_pricing_workflow` 表结构
|
||||
2. 不新增密文字段、副本字段或检索字段
|
||||
3. 实施前执行历史流程数据清空脚本
|
||||
4. 清空范围仅限贷款定价流程相关存量数据
|
||||
|
||||
因为 `custName`、`idNum` 不再承担查询职责,所以现有字段直接存密文即可。
|
||||
|
||||
## 11. 错误处理设计
|
||||
|
||||
本次不做兼容性补丁逻辑,错误直接失败:
|
||||
|
||||
1. 加密配置缺失
|
||||
创建流程直接失败,不允许明文落库
|
||||
|
||||
2. 解密失败
|
||||
详情查询失败,模型调用失败,并记录明确错误日志
|
||||
|
||||
3. 历史脏数据
|
||||
通过清空存量数据消除,不增加“密文/明文混读”兼容判断
|
||||
|
||||
4. 前端展示
|
||||
前端只消费后端结果,不承担兜底脱敏职责
|
||||
|
||||
## 12. 测试与验收设计
|
||||
|
||||
### 12.1 后端验收
|
||||
|
||||
1. 创建个人贷款定价流程,校验数据库 `cust_name`、`id_num` 为密文
|
||||
2. 创建企业贷款定价流程,校验数据库 `cust_name`、`id_num` 为密文
|
||||
3. 列表查询仅支持通过 `custIsn` 命中
|
||||
4. 列表返回中的 `custName` 为脱敏值
|
||||
5. 详情返回中的 `custName`、`idNum` 为脱敏值
|
||||
6. 模型调用链路成功,证明服务内部解密逻辑成立
|
||||
7. 配置缺失时创建流程失败,确认不会明文入库
|
||||
|
||||
### 12.2 前端验收
|
||||
|
||||
1. 列表页查询项已移除客户名称,改为客户内码
|
||||
2. 列表页客户名称展示为脱敏值
|
||||
3. 个人详情页客户名称、证件号码展示为脱敏值
|
||||
4. 企业详情页客户名称、证件号码展示为脱敏值
|
||||
5. 创建流程、查看详情、设定执行利率等既有功能不受影响
|
||||
|
||||
## 13. 风险与控制
|
||||
|
||||
### 风险一:模型调用读取到密文
|
||||
|
||||
控制方式:
|
||||
|
||||
- 在 `LoanPricingModelService` 调用模型前显式解密
|
||||
- 用测试覆盖模型调用前数据组装逻辑
|
||||
|
||||
### 风险二:返回链路遗漏脱敏
|
||||
|
||||
控制方式:
|
||||
|
||||
- 统一在服务层返回前调用展示服务
|
||||
- 列表 VO 与详情 VO 都纳入测试覆盖
|
||||
|
||||
### 风险三:历史明文和新密文混杂
|
||||
|
||||
控制方式:
|
||||
|
||||
- 实施前清空贷款定价流程历史数据
|
||||
- 不保留兼容读取分支
|
||||
|
||||
## 14. 范围与非目标
|
||||
|
||||
本次包含:
|
||||
|
||||
- 贷款定价流程建单入库加密
|
||||
- 贷款定价流程列表和详情展示脱敏
|
||||
- 贷款定价流程查询条件收口为客户内码
|
||||
- 贷款定价流程存量数据清空处理
|
||||
|
||||
本次不包含:
|
||||
|
||||
- 模型输出表加密改造
|
||||
- 系统其他模块的敏感字段改造
|
||||
- 前后端传输层字段加密
|
||||
- 密钥托管平台接入
|
||||
- 基于角色的明文查看权限
|
||||
|
||||
## 15. 设计结论
|
||||
|
||||
本次采用“应用层统一 AES 加解密 + 返回前统一脱敏”的方式,对贷款定价流程中的 `custName`、`idNum` 完成存储加密和展示脱敏改造。
|
||||
|
||||
该方案满足当前客户安全要求,并保持实现路径最短、责任边界清晰、业务链路闭环完整。
|
||||
@@ -0,0 +1,32 @@
|
||||
# 贷款定价流程客户敏感信息加密设计实施记录
|
||||
|
||||
## 实施时间
|
||||
|
||||
- 2026-03-30
|
||||
|
||||
## 修改内容
|
||||
|
||||
- 新增贷款定价流程客户敏感信息加密改造设计文档
|
||||
- 明确本次范围仅覆盖贷款定价流程主链
|
||||
- 明确敏感字段限定为 `custName`、`idNum`
|
||||
- 明确采用应用层 AES 加解密与返回前统一脱敏方案
|
||||
- 明确列表查询改为仅支持客户内码 `custIsn`
|
||||
- 明确存量数据处理方式为直接清空,不做迁移
|
||||
|
||||
## 文档路径
|
||||
|
||||
- `doc/2026-03-30-loan-pricing-sensitive-data-encryption-design.md`
|
||||
- `doc/implementation-report-2026-03-30-loan-pricing-sensitive-data-encryption-design.md`
|
||||
|
||||
## 设计结论
|
||||
|
||||
- `loan_pricing_workflow.cust_name`、`loan_pricing_workflow.id_num` 改为密文存储
|
||||
- 贷款定价流程列表页、详情页仅展示脱敏值
|
||||
- 前端不承担加解密职责
|
||||
- 模型调用前由后端服务内部解密敏感字段
|
||||
|
||||
## 说明
|
||||
|
||||
- 设计文档已按当前仓库习惯保存到 `doc/` 目录
|
||||
- 仓库约束禁止启用 subagent,因此本次未执行基于 subagent 的设计文档复审流程,改为人工复审
|
||||
- 本次仅完成设计,不包含实施代码修改
|
||||
Reference in New Issue
Block a user