# sgchen-security
**Repository Path**: chenshaogui/sgchen-security
## Basic Information
- **Project Name**: sgchen-security
- **Description**: spring 接口请求加解密处理、数据库加密存储处理、接口敏感数据脱敏处理
- **Primary Language**: Unknown
- **License**: Apache-2.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 1
- **Forks**: 4
- **Created**: 2025-06-10
- **Last Updated**: 2025-09-08
## Categories & Tags
**Categories**: Uncategorized
**Tags**: 数据加密, 数据脱敏
## README
# 数据传输加解密及数据存储加解密
基于SpringBoot和Mybatis的数据安全处理,在数据持久层对数据进行加/解密,接口请求加密解密,接口的脱敏处理。
1、通过注解在保存数据的时候将指定字段进行加密处理,查询时自动解密\
2、通过注解在查询数据的时候对指定字段进行脱敏处理\
3、通过实现接口请求和相应数据的解密加密以及敏感数据的脱敏处理
*** 前端秘钥存储可以使用用户密码加密,后端秘钥配置可以用-Djasypt.encryptor.password= 加密存储 ***
SpringBoot+MyBatis-Plus ,HuTool的工具包、Lombok插件以及Bouncy Castle加密包、fastjson2工具
https://gitee.com/chenshaogui/sgchen-security
数据传输加解密及数据存储加解密使用手册
# 一、概要介绍
数据传输各模式对比
| 加密类型 | 模式 | 核心特点 | 优点 | 缺点 | 典型用途 |
|-------|-----------|-------------------|---------------|------------------|-------------------|
| 对称加密 | ECB(无 IV) | 块独立加密,无 IV | 简单、效率高 | 密文块重复,安全性极差 | 已弃用,仅早期低安全场景 |
| 对称加密 | 固定 IV | 用固定 IV 混合加密 | 实现简单,比 ECB 安全 | 明文开头重复时密文重复,安全性弱 | 内部低敏感、短周期传输 |
| 对称加密 | 动态 IV | 随机 IV,随密文传输 | 安全性高,无密文重复 | 需传输 IV,依赖 IV 随机性 | HTTPS、敏感 API、文件加密 |
| 非对称混合 | 请求头密钥模式 | 单次请求独立生成对称密钥,公钥加密 | 安全高效,适合单次请求 | 每次请求有非对称加密开销 | 开放平台 API、一次性数据提交 |
| 非对称混合 | 会话模式 | 会话初期协商会话密钥,后续对称加密 | 效率极高,适合持续通信 | 会话密钥泄露影响整个会话 | 即时通讯、VPN、在线会议 |
## 非对称秘钥算法介绍
| **算法** | **密钥长度范围** | **推荐密钥长度** | **安全强度(位)** |
|------------|---------------------|---------------|---------------|
| RSA | 1024-4096 位 | 2048 位 | 约 112 位 |
| DSA | 1024-3072 位 | 2048 位 | 约 112 位 |
| ElGamal | 1024-4096 位 | 2048 位 | 约 112 位 |
| ECDSA/ECDH | P-256, P-384, P-521 | P-256 (128 位) | 128/192/256 位 |
| SM2 | SM2-P-256 | 256 位 | 128 位 |
# 二、SpringBoot项目公共配置
## 依赖包引入
```xml
org.springframework.boot
spring-boot-starter-web
2.7+
com.baomidou
mybatis-plus-boot-starter
3.5+
cn.hutool
hutool-all
5.8+
org.springframework.boot
spring-boot-starter-data-redis
2.7+
```
## 引入加解密工具Maven包
```xml
io.gitee.chenshaogui
sgchen-security
1.0.42
```
## springBoot启动类加注解
```java
@SpringBootApplication
@EnableDataSecurity
public class DataSecurityApplication {
public static void main(String[] args) {
SpringApplication.run(DataSecurityApplication.class, args);
}
}
```
# 三、*数据存储*
## *项目集成秘钥参数配置*
```java
@Configuration
public class DataSecurityConfig {
@Bean
public SecretConfig secretConfig() {
return SecretConfig.builder()
.dbSecretKey("加密秘钥")
// 数据存储加密算法
.dbAlgorithm(SecretAlgorithm.PKCS7)
.build();
}
}
```
## *开发使用方法*
### 实体类(VO、DTO、PO等)配置
```markdown
@EncryptEntity 实体类上注解
@EncryptField 实体类上需要新增 查询 加解密字段注解
```
实体类可以加@DesensitizedField脱敏字段查出的结果脱敏,但不建议这样做。会影响后面的结果业务处理
### 实体类代码样例参考
```java
@Data
@TableName("account")
@EncryptEntity
public class AccountPo {
/**
* id
*/
@TableId(value = "id", type= IdType.AUTO)
private Integer id;
/**
* 账号
*/
@EncryptField
private String account;
/**
* 密码
*/
@EncryptField
private String password;
/**
* email
*/
private String email;
}
```
### Mybatis Mapper文件查询方式
```java
// 使用Mapper.xml查询时单个参数注解
@EncryptParam
List getInfoByAccount(@EncryptParam("account") @Param("account") String account);
// 当参数是对象时只需要在类上加注解
List listByFilter(@Param("entity") AccountPo accountPo);
```
### Mybatis Wrapper内置Api调用使用
```java
public List getInfoByAccount(AccountPo accountPo) {
EncryptLambdaQueryWrapper queryWrapper = new EncryptLambdaQueryWrapper<>();
queryWrapper.eq(AccountPo::getAccount, accountPo.getAccount());
return accountMapper.selectList(queryWrapper);
}
```
查询时使用 EncryptLambdaQueryWrapper
更新时调用 EncryptLambdaUpdateWrapper
### Mapper层代码样例参考
```java
@Service
public class AccountServiceImpl implements AccountService {
@Resource
private AccountMapper accountMapper;
@Override
public void addAccount(AccountPo accountPo) {
accountMapper.insert(accountPo);
}
@Override
public List queryAllWrapper() {
return accountMapper.selectList(Wrappers.emptyWrapper());
}
@Override
public void updatePasswordByAccount(String account, String password) {
accountMapper.updatePasswordByAccount(account, password);
}
@Override
public void updateByIdWrapper(AccountPo accountPo) {
accountMapper.updateById(accountPo);
}
@Override
public List getInfoByMapperParams(AccountPo accountPo) {
return accountMapper.getInfoByAccount(accountPo.getAccount());
}
@Override
public List getInfoByWrapper(AccountPo accountPo) {
EncryptLambdaQueryWrapper queryWrapper = new EncryptLambdaQueryWrapper<>();
queryWrapper.eq(AccountPo::getAccount, accountPo.getAccount());
return accountMapper.selectList(queryWrapper);
}
@Override
public List listByMapperEntity(AccountPo accountPo) {
return accountMapper.listByFilter(accountPo);
}
@Override
public AccountPo infoByWrapperId(Integer id) {
return accountMapper.selectById(id);
}
@Override
public void updateByIdUpdateWrapper(AccountPo accountPo) {
EncryptLambdaUpdateWrapper queryWrapper = new EncryptLambdaUpdateWrapper<>();
queryWrapper.eq(AccountPo::getId, accountPo.getId());
queryWrapper.set(AccountPo::getEmail,accountPo.getEmail());
queryWrapper.set(AccountPo::getAccount,accountPo.getAccount());
accountMapper.update(null,queryWrapper);
}
@Override
public void updateUpdateWrapper(AccountPo accountPo) {
EncryptLambdaQueryWrapper queryWrapper = new EncryptLambdaQueryWrapper<>();
queryWrapper.eq(AccountPo::getId, accountPo.getId());
accountMapper.update(accountPo,queryWrapper);
}
}
```
# 四、数据传输
## *开发使用方法(包含数据脱敏)*
### Controller层类注解:类注解方式(方法和类注解方式二选一)
```java
@EncryptController({
@DesensitizedUnit(field = "secondPhone", mode = DesensitizedMode.mobile),
@DesensitizedUnit(field = "secondReceiver", mode = DesensitizedMode.name),
@DesensitizedUnit(field = "auditor", mode = DesensitizedMode.name),
@DesensitizedUnit(field = "secondAddress", mode = DesensitizedMode.address),
@DesensitizedUnit(field = "userAccount", mode = DesensitizedMode.mobile)
})
public class AccountController {}
```
### Controller层方法注解:方法上的加密请求注解(方法和类注解方式二选一)
```java
@EncryptRequest({
@DesensitizedUnit(field = "secondPhone", mode = DesensitizedMode.mobile),
@DesensitizedUnit(field = "secondReceiver", mode = DesensitizedMode.name),
@DesensitizedUnit(field = "auditor", mode = DesensitizedMode.name),
@DesensitizedUnit(field = "secondAddress", mode = DesensitizedMode.address),
@DesensitizedUnit(field = "userAccount", mode = DesensitizedMode.mobile)
})
public AjaxResult queryAllWrapper() {}
```
## *项目集成秘钥参数配置*
### 对称和非对称自定义加密
使用其他对称加密算法
```html
PKCS5("AES/ECB/PKCS5Padding", true, 128, 16),
PKCS7("AES/ECB/PKCS7Padding", true, 128, 16),
CBC_PKCS7("AES/CBC/PKCS7Padding", true, 128, 16),
SM4_ECB_PKCS7("SM4/ECB/PKCS7Padding", true, 128, 16),
SM4_CBC_PKCS7("SM4/CBC/PKCS7Padding", true, 128, 16),
/**
* 以下是严格模式,当加解密失败时抛出异常
*/
PKCS5_STRICT("AES/ECB/PKCS5Padding", false, 128, 16),
PKCS7_STRICT("AES/ECB/PKCS7Padding", false, 128, 16),
CBC_PKCS7_STRICT("AES/CBC/PKCS7Padding", false, 128, 16),
SM4_ECB_PKCS7_STRICT("SM4/ECB/PKCS7Padding", false, 128, 16),
SM4_CBC_PKCS7_STRICT("SM4/CBC/PKCS7Padding", false, 128, 16),
/**
* 自定义算法占位符
*/
CUSTOM_ALGORITHM(null, null, 128, 16);
public static synchronized void configureCustomAlgorithm(String algorithm, Boolean isSkipError, Integer keySize, Integer ivSize){}
```
使用其他的非对称秘钥算法
```html
/**
* RSA 非对称加密混合,秘钥会话模式
*/
RSA_WITH_SESSION("RSA", "RSA,秘钥会话模式", RequestKeyTransMode.SESSION, 2048),
/**
* 非对称加密混合,请求头秘钥模式
*/
RSA_WITH_HEADER("RSA", "RSA,请求头秘钥模式", RequestKeyTransMode.HEADER, 2048),
/**
* ECC 非对称加密混合,秘钥会话模式
*/
ECDH_WITH_SESSION("ECDH", "ECDH,秘钥会话模式", RequestKeyTransMode.SESSION, 256),
/**
* ECC 非对称加密模式
*/
ECDH_WITH_HEADER("ECDH", "ECDH,请求头秘钥模式", RequestKeyTransMode.HEADER, 256),
/**
* ELGAMAL 非对称加密混合,秘钥会话模式
*/
ELGAMAL_WITH_SESSION("ElGamal", "ELGAMAL,秘钥会话模式", RequestKeyTransMode.SESSION, 256),
/**
* ElGamal 非对称加密模式
*/
ELGAMAL_WITH_HEADER("ElGamal", "ElGamal,请求头秘钥模式", RequestKeyTransMode.HEADER, 256),
/**
* SM2 非对称加密混合,秘钥会话模式
*/
SM2_WITH_SESSION("EC", "SM2,秘钥会话模式", RequestKeyTransMode.SESSION, 256),
/**
* SM2 非对称加密模式
*/
SM2_WITH_HEADER("EC", "SM2,请求头秘钥模式", RequestKeyTransMode.HEADER, 256),
/**
* 自定义算法占位符
*/
CUSTOM_ALGORITHM(null, null, null, null);
public static synchronized void configureCustomAlgorithm(String algorithm, String description, RequestKeyTransMode keyTransMode, Integer keySize)
```
可以调用configureCustomAlgorithm方法配置自定义算法,key和iv的长度,自定义算法代码样例:
```java
@Configuration
public class DataSecurityConfig {
@Bean
public SecretConfig secretConfig() {
// 配置对称秘钥的自定义算法
SecretAlgorithm.configureCustomAlgorithm("DES/CBC/PKCS5Padding", false, 56, 8);
// 配置非对称秘钥的自定义算法
RequestAsymmetricMode.configureCustomAlgorithm("RSA", "RSA,1024大小的算法", RequestKeyTransMode.SESSION, 1024);
return SecretConfig.builder()
.reqAlgorithm(SecretAlgorithm.CUSTOM_ALGORITHM)
.requestAsymmetricMode(RequestAsymmetricMode.CUSTOM_ALGORITHM)
.dbSecretKey("数据存储加密秘钥") // 不使用可以不配置
// 数据存储加解密算法
.dbAlgorithm(SecretAlgorithm.PKCS7) // 不使用可以不配置
.build();
}
}
```
### Feign调用时使用方法
```java
@Configuration
public class FeignRequestInterceptor implements RequestInterceptor {
@Bean
public feign.Logger.Level loggerLevel() {
return feign.Logger.Level.FULL;
}
@Override
public void apply(RequestTemplate requestTemplate) {
requestTemplate.header(SecurityConstants.FEIGN_CLIENT_CALL, "true");
// to do something
}
}
```
### 对称加密【ECB(无IV)模式】: AES、SM4、自定义对称加密
#### 加解密流程
1.请求使用固定秘钥加密的数据传输
客户端 → 发送【固定秘钥加密 的请求数据】→ 服务端
服务端 → 固定秘钥加密解密请求数据 → 处理业务 → 用客户端固定秘钥加密响应 → 返回客户端
#### 使用方法
* 1、项目秘钥配置【使用AES/ECB/PKCS7Padding秘钥为例】
```java
@Configuration
public class DataSecurityConfig {
@Bean
public SecretConfig secretConfig() {
return SecretConfig.builder()
.reqSecretKey("请求存储加密秘钥")
.reqAlgorithm(SecretAlgorithm.PKCS7)
.dbSecretKey("数据存储加密秘钥") // 不使用可以不配置
// 数据存储加解密算法
.dbAlgorithm(SecretAlgorithm.PKCS7) // 不使用可以不配置
.build();
}
}
```
* 2、请求数据传输用例(用ApiPost模拟)
| 步骤 | 处理方法 |
|:------:|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 参数加密 | const key = CryptoJS.enc.Utf8.parse("0123456789abcdeffedcba9876543210");
//加密方法
function Encrypt(word) {
let srcs = CryptoJS.enc.Utf8.parse(typeof word === "string" ? word : JSON.stringify(word));
let encrypted = CryptoJS.AES.encrypt(srcs, key, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7 });
return encrypted.toString();
}
let requests = Encrypt(request.request_bodys);
pm.request.body.raw = requests;
|
| 请求数据 | POST: localhost:9898/data-security/account/getInfoByWrapper
RequestBody请求数据:
MCORifq5PMEjU8+q3F9A0nkJSH/iziLmuuL0HIpBk4M=
|
| 返回数据解密 | const key = CryptoJS.enc.Utf8.parse("0123456789abcdeffedcba9876543210");
//解密方法
function Decrypt(word) {
let decrypt = CryptoJS.AES.decrypt(word.replaceAll("\"", ""), key, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7 });
let decryptedStr = decrypt.toString(CryptoJS.enc.Utf8);
return decryptedStr.toString();
}
let responses = Decrypt(response.raw.responseText);
console.log(JSON.parse(responses))
pm.response.setBody(responses);
|
### 对称加密【固定IV】: AES、SM4、自定义对称加密
#### 加解密流程
1.请求使用固定秘钥和固定IV加密的数据传输
客户端 → 发送【固定秘钥和固定IV加密 的请求数据】→ 服务端
服务端 → 固定秘钥和固定IV加密解密请求数据 → 处理业务 → 用客户端固定秘钥和固定IV加密响应 → 返回客户端
#### 使用方法
* 1、项目秘钥配置【使用固定秘钥和固定IV加密为例】
```java
@Configuration
public class DataSecurityConfig {
@Bean
public SecretConfig secretConfig() {
return SecretConfig.builder()
.reqSecretKey("0123456789abcdeffedcba9876543210")
.reqAlgorithm(SecretAlgorithm.CBC_PKCS7)
.reqSecretIV("0102030405060708")
.dbSecretKey("testtest12345678")
.dbAlgorithm(SecretAlgorithm.PKCS7)
.build();
}
}
```
* 2、请求数据传输用例(采用16进制的IV模式,16进制的key,base64的IV请参考:动态Base64编码IV,前端用ApiPost模拟)
| 步骤 | 处理方法 |
|:------:|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 参数加密 | let key = "0123456789abcdeffedcba9876543210";
const iv = CryptoJS.enc.Utf8.parse('0102030405060708'); //十六位十六进制数作为密钥偏移量
//加密方法
function Encrypt(word) {
let srcs = CryptoJS.enc.Utf8.parse(typeof word === "string" ? word : JSON.stringify(word));
key = CryptoJS.enc.Hex.parse(key);
let encrypted = CryptoJS.AES.encrypt(srcs, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 });
return encrypted.toString();
}
let requests = Encrypt(request.request_bodys);
pm.request.body.raw = requests;
|
| 请求数据 | POST: localhost:9898/data-security/account/getInfoByWrapper
RequestBody请求数据:
aHoFvEIrf7wDCT3jlsCiMizWg5KAu000+fI/HPW7IMY=
|
| 返回数据解密 | let key = "0123456789abcdeffedcba9876543210";
const iv = CryptoJS.enc.Utf8.parse('0102030405060708');
//解密方法
function Decrypt(word) {
key = CryptoJS.enc.Hex.parse(key);
let decrypt = CryptoJS.AES.decrypt(word.replaceAll("\"", ""), key, { mode: CryptoJS.mode.CBC,iv:iv,padding: CryptoJS.pad.Pkcs7 });
let decryptedStr = decrypt.toString(CryptoJS.enc.Utf8);
return decryptedStr.toString();
}
let responses = Decrypt(response.raw.responseText);
console.log(JSON.parse(responses))
pm.response.setBody(responses);
|
### 对称加密【动态16进制IV】: AES、SM4、自定义对称加密
#### 加解密流程
1.请求使用固定秘钥和动态16进制IV加密的数据传输
客户端 → 发送【固定秘钥和动态16进制IV加密 的请求数据】→ 服务端
服务端 → 固定秘钥和动态16进制IV加密解密请求数据 → 处理业务 → 用客户端固定秘钥和动态16进制IV加密响应 → 返回客户端
#### 使用方法
* 1、项目秘钥配置【使用固定秘钥和动态16进制IV加密为例】
```java
@Configuration
public class DataSecurityConfig {
@Bean
public SecretConfig secretConfig() {
return SecretConfig.builder()
.reqSecretKey("0123456789abcdeffedcba9876543210")
.reqAlgorithm(SecretAlgorithm.SM4_PKCS7)
.dbSecretKey("testtest12345678")
.dbAlgorithm(SecretAlgorithm.PKCS7)
.build();
}
}
```
* 2、请求数据传输用例(采用16进制的IV模式,16进制的key,base64的IV请参考:动态Base64编码IV,前端用ApiPost模拟)
| 步骤 | 处理方法 |
|:------:|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 参数加密 | // 设置你的密钥和IV(实际项目中应从配置或环境变量获取)
var secretKey = "0123456789abcdeffedcba9876543210"; // 必须是16字节(128位)
// 生成 16 字节随机 IV(以 WordArray 格式表示)
const iv = CryptoJS.lib.WordArray.random(16);
// 转换为十六进制字符串(可读性更好)
const ivHex = iv.toString(CryptoJS.enc.Hex);
// 请求前脚本 - SM4加密请求数据并以Base64格式输出
function encryptData(word, key, iv) {
// 使用SM4-CBC模式加密
let encryptedHex = sm4.encrypt(word, key, { mode: 'cbc', iv: iv }) // 加密,cbc 模式
// 将16进制字符串转换为字节数组
var bytes = hexToBytes(encryptedHex);
// 将字节数组转换为Base64
var encryptedBase64 = bytesToBase64(bytes);
return encryptedBase64;
}
// 辅助函数:16进制字符串转字节数组
function hexToBytes(hex) {
var bytes = [];
for (var i = 0; i < hex.length; i += 2) {
bytes.push(parseInt(hex.substr(i, 2), 16));
}
return bytes;
}
// 辅助函数:字节数组转Base64
function bytesToBase64(bytes) {
var base64Chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
var result = '';
var i = 0;
while (i < bytes.length) {
var byte1 = bytes[i++];
var byte2 = i < bytes.length ? bytes[i++] : 0;
var byte3 = i < bytes.length ? bytes[i++] : 0;
var enc1 = byte1 >> 2;
var enc2 = ((byte1 & 0x03) << 4) \| (byte2 >> 4);
var enc3 = ((byte2 & 0x0F) << 2) \| (byte3 >> 6);
var enc4 = byte3 & 0x3F;
if (i > bytes.length + 1) {
enc3 = enc4 = 64;
} else if (i > bytes.length) {
enc4 = 64;
}
result += base64Chars.charAt(enc1) + base64Chars.charAt(enc2) +
base64Chars.charAt(enc3) + base64Chars.charAt(enc4);
}
return result;
}
// 获取请求数据
var requestData = pm.request.body.raw;
// 加密数据
var encryptedData = encryptData(requestData, secretKey, ivHex);
// 设置加密后的数据到请求体
pm.request.body.raw = encryptedData;
// 可选:添加加密信息头
pm.request.headers.upsert({
key: 'X-Encrypted-IV',
value: ivHex
});
|
| 请求数据 | POST: localhost:9898/data-security/account/getInfoByWrapper
RequestBody请求数据:
4mDrMKIsb7soAEDD/d6QvmaHwIOB3cbkygUmJlp1KTgRT4qVYy5giiSFwtDD1KB+
|
| 返回数据解密 | // 响应后脚本 - 解密SM4加密的响应数据
// 设置你的密钥和IV(实际项目中应从配置或环境变量获取)
var secretKey = "0123456789abcdeffedcba9876543210"; // 必须是16字节(128位)
function decryptData(ciphertext, key, iv) {
// 使用SM4-CBC模式解密
let decryptStr = ciphertext.replaceAll("\"", "");
// 将Base64转换为字节数组
var ciphertextBytes = base64ToBytes(decryptStr);
// 将字节数组转换为16进制字符串
var ciphertextHex = bytesToHex(ciphertextBytes);
// key = CryptoJS.enc.Hex.parse(key);
// 使用SM4-CBC模式加密
var decryptedResult = sm4.decrypt(ciphertextHex, key, { mode: 'cbc', iv: iv })
return decryptedResult;
}
// 辅助函数:Base64转字节数组
function base64ToBytes(base64) {
var base64Chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
base64 = base64.replace(/=+$/, '');
var bytes = [];
for (var i = 0; i < base64.length; i += 4) {
var enc1 = base64Chars.indexOf(base64.charAt(i));
var enc2 = base64Chars.indexOf(base64.charAt(i + 1));
var enc3 = base64Chars.indexOf(base64.charAt(i + 2));
var enc4 = base64Chars.indexOf(base64.charAt(i + 3));
var byte1 = (enc1 << 2) \| (enc2 >> 4);
var byte2 = ((enc2 & 0x0F) << 4) \| (enc3 >> 2);
var byte3 = ((enc3 & 0x03) << 6) \| enc4;
bytes.push(byte1);
if (enc3 !== 64) bytes.push(byte2);
if (enc4 !== 64) bytes.push(byte3);
}
return bytes;
}
// 辅助函数:字节数组转16进制字符串
function bytesToHex(bytes) {
var hex = [];
for (var i = 0; i < bytes.length; i++) {
var b = bytes[i];
hex.push((b < 16 ? '0' : '') + b.toString(16));
}
return hex.join('');
}
// 获取响应数据
var responseData = pm.response.text();
const envIV = pm.response.headers.get('X-Encrypted-IV');
// 解密数据
var decryptedData = decryptData(responseData, secretKey, envIV);
// 尝试解析为JSON(如果是JSON格式)
try {
var jsonData = JSON.parse(decryptedData);
pm.response.json = function () { return jsonData; };
} catch (e) {
// 如果不是JSON,保留原始解密文本
pm.response.text = function () { return decryptedData; };
}
// 记录解密结果到控制台
console.log("解密响应:", decryptedData);
|
### 对称加密【动态Base64编码IV】: AES、SM4、自定义对称加密
#### 加解密流程
1.请求使用固定秘钥和动态base64编码IV加密的数据传输
客户端 → 发送【固定秘钥和动态base64编码IV加密 的请求数据】→ 服务端
服务端 → 固定秘钥和动态base64编码IV加密解密请求数据 → 处理业务 → 用客户端固定秘钥和动态base64编码IV加密响应 → 返回客户端
#### 使用方法
* 1、项目秘钥配置【使用固定秘钥和base64编码IV加密为例】
```java
@Configuration
public class DataSecurityConfig {
@Bean
public SecretConfig secretConfig() {
return SecretConfig.builder()
.reqSecretKey("0123456789abcdeffedcba9876543210")
.reqAlgorithm(SecretAlgorithm.CBC_PKCS7)
.dbSecretKey("testtest12345678")
.dbAlgorithm(SecretAlgorithm.PKCS7)
.build();
}
}
```
* 2、请求数据传输用例(采用动态Base64编码的IV模式,16进制的key,前端用ApiPost模拟)
| 步骤 | 处理方法 |
|:------:|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 参数加密 | // 设置你的密钥和IV(实际项目中应从配置或环境变量获取)
var secretKey = "0123456789abcdeffedcba9876543210"; // 必须是16字节(128位)
// 生成 16 字节随机 IV(以 WordArray 格式表示)
var iv = CryptoJS.lib.WordArray.random(16);
// 转换为 Base64 字符串(适合在 HTTP 请求头中传输)
var ivBase64 = iv.toString(CryptoJS.enc.Base64);
// 转换为十六进制字符串(可读性更好)
var ivHex = iv.toString(CryptoJS.enc.Hex);
// 请求前脚本 - SM4加密请求数据并以Base64格式输出
function encryptData(word, key, iv) {
let srcs = CryptoJS.enc.Utf8.parse(typeof word === "string" ? word : JSON.stringify(word));
let keyStr = CryptoJS.enc.Utf8.parse(key);
keyStr = CryptoJS.enc.Hex.parse(key);
let ivstr = CryptoJS.enc.Base64.parse(iv);
let encrypted = CryptoJS.AES.encrypt(srcs, keyStr, { iv: ivstr, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 });
console.log("加密字符串", encrypted.toString())
return encrypted.toString();
}
// 辅助函数:16进制字符串转字节数组
function hexToBytes(hex) {
var bytes = [];
for (var i = 0; i < hex.length; i += 2) {
bytes.push(parseInt(hex.substr(i, 2), 16));
}
return bytes;
}
// 辅助函数:字节数组转Base64
function bytesToBase64(bytes) {
var base64Chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
var result = '';
var i = 0;
while (i < bytes.length) {
var byte1 = bytes[i++];
var byte2 = i < bytes.length ? bytes[i++] : 0;
var byte3 = i < bytes.length ? bytes[i++] : 0;
var enc1 = byte1 >> 2;
var enc2 = ((byte1 & 0x03) << 4) \| (byte2 >> 4);
var enc3 = ((byte2 & 0x0F) << 2) \| (byte3 >> 6);
var enc4 = byte3 & 0x3F;
if (i > bytes.length + 1) {
enc3 = enc4 = 64;
} else if (i > bytes.length) {
enc4 = 64;
}
result += base64Chars.charAt(enc1) + base64Chars.charAt(enc2) +
base64Chars.charAt(enc3) + base64Chars.charAt(enc4);
}
return result;
}
// 获取请求数据
var requestData = pm.request.body.raw;
var encryptedData = encryptData(requestData, secretKey, ivBase64);
// 设置加密后的数据到请求体
pm.request.body.raw = encryptedData;
// 可选:添加加密信息头
pm.request.headers.upsert({
key: 'X-Encrypted-IV',
value: ivBase64
});
|
| 请求数据 | POST: localhost:9898/data-security/account/getInfoByWrapper
RequestBody请求数据:
CbWiLmLavpkTaEglW9pNdCocnhQDiI5Ewt+6evPNBtnjBTOKub3szj10FMPf0yEw
|
| 返回数据解密 | // 响应后脚本 - 解密SM4加密的响应数据
// 设置你的密钥和IV(实际项目中应从配置或环境变量获取)
var secretKey = "0123456789abcdeffedcba9876543210"; // 必须是16字节(128位)
function decryptData(ciphertext, key, iv) {
let decryptStr = ciphertext.replaceAll("\"", "");
let keyStr = CryptoJS.enc.Utf8.parse(key);
keyStr = CryptoJS.enc.Hex.parse(key);
let ivstr = CryptoJS.enc.Base64.parse(iv);
var decryptedResult = CryptoJS.AES.decrypt(decryptStr, keyStr, { iv: ivstr, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 });
let decryptedStr = CryptoJS.enc.Utf8.stringify(decryptedResult);
return decryptedStr.toString();
}
// 获取响应数据
var responseData = pm.response.text();
const envIV = pm.response.headers.get('X-Encrypted-IV');
// 解密数据
var decryptedData = decryptData(responseData, secretKey, envIV);
// 尝试解析为JSON(如果是JSON格式)
try {
var jsonData = JSON.parse(decryptedData);
pm.response.json = function () { return jsonData; };
} catch (e) {
// 如果不是JSON,保留原始解密文本
pm.response.text = function () { return decryptedData; };
}
// 记录解密结果到控制台
console.log("解密响应:", decryptedData);
|
### 非对称加密混合请求头秘钥模式【秘钥对称加密、传输数据非对称加密】: RSA、SM2、ECC(ECDH、ECDSA)、ElGamal、自定义非对称加密
#### 加解密流程(需要Redis支持)
1. 首次创建会话时传输对称密钥
客户端 → 生成对称密钥
2.请求携带客户端秘钥以及客户端秘钥加密的数据
客户端 → 发送【客户端秘钥加密的数据 + 非对称加密客户端秘钥 的请求数据】→ 服务端
服务端 → 用公钥解密客户端密钥 → 使用客户端秘钥解密请求数据 → 处理业务 → 用客户端秘钥加密响应 → 返回客户端
#### 默认参数配置(非对称密钥对有效期)
```yaml
# 混合加密模式
csg-tsc:
rsa-key:
# RSA密钥有效期(小时),默认24小时
expiryHours: 24
```
当没有配置数据时将使用默认配置
#### 使用方法(多项目共用一个Redis,客户端编码必须配置)
* 1、项目秘钥配置【使用SM4加密传输数据,SM2传输秘钥为例】
```java
@Configuration
public class DataSecurityConfig {
@Bean
public SecretConfig secretConfig() {
return SecretConfig.builder()
.reqAlgorithm(SecretAlgorithm.SM4_CBC_PKCS7)
.requestAsymmetricMode(RequestAsymmetricMode.SM2_WITH_HEADER)
.dbSecretKey("数据存储加密秘钥") // 不使用可以不配置
// 数据存储加解密算法
.dbAlgorithm(SecretAlgorithm.PKCS7) // 不使用可以不配置
.clientCode("system") // 客户端编码
.build();
}
}
```
* 2、前端获取公钥
```html
Get: localhost:9898/data-security/api/asymmetricTSC/public-key
Response响应数据:
{
"publicKey": "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEFgFkoXDTKyP2jhigRUlrI3qO0LxZ3emioBNS8ReMYW19PMSEw+90mWmWBDcF8h0eUwDmpMWaXApfX2vRWWfwtw==",
"version": "c72255c86c5f4993b39dea9458140fd7"
}
```
* 3、前端使用公钥加密私钥
--自定义方法处理
* 4、请求数据传输用例(采用16进制的IV模式,base64的IV请参考:动态Base64编码IV,前端用ApiPost模拟)
| 步骤 | 处理方法 |
|:------:|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 参数加密 | // 设置你的密钥和IV(实际项目中应从配置或环境变量获取)
var secretKey = "0123456789abcdeffedcba7896543210"; // 必须是16字节(128位)
// 生成 16 字节随机 IV(以 WordArray 格式表示)
var iv = CryptoJS.lib.WordArray.random(16);
// 转换为 Base64 字符串(适合在 HTTP 请求头中传输)
// 转换为十六进制字符串(可读性更好)
var ivHex = iv.toString(CryptoJS.enc.Hex);
// 请求前脚本 - SM4加密请求数据并以Base64格式输出
function encryptData(word, key, iv) {
// 如果数据是对象,转换为JSON字符串
// 使用SM4-CBC模式加密
let encryptedHex = sm4.encrypt(word, key, { mode: 'cbc', iv: iv }) // 加密,cbc 模式
// 将16进制字符串转换为字节数组
var bytes = hexToBytes(encryptedHex);
// 将字节数组转换为Base64
var encryptedBase64 = bytesToBase64(bytes);
return encryptedBase64;
}
// 辅助函数:16进制字符串转字节数组
function hexToBytes(hex) {
var bytes = [];
for (var i = 0; i < hex.length; i += 2) {
bytes.push(parseInt(hex.substr(i, 2), 16));
}
return bytes;
}
// 辅助函数:字节数组转Base64
function bytesToBase64(bytes) {
var base64Chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
var result = '';
var i = 0;
while (i < bytes.length) {
var byte1 = bytes[i++];
var byte2 = i < bytes.length ? bytes[i++] : 0;
var byte3 = i < bytes.length ? bytes[i++] : 0;
var enc1 = byte1 >> 2;
var enc2 = ((byte1 & 0x03) << 4) \| (byte2 >> 4);
var enc3 = ((byte2 & 0x0F) << 2) \| (byte3 >> 6);
var enc4 = byte3 & 0x3F;
if (i > bytes.length + 1) {
enc3 = enc4 = 64;
} else if (i > bytes.length) {
enc4 = 64;
}
result += base64Chars.charAt(enc1) + base64Chars.charAt(enc2) +
base64Chars.charAt(enc3) + base64Chars.charAt(enc4);
}
return result;
}
// 获取请求数据
var requestData = pm.request.body.raw;
var encryptedData = encryptData(requestData, secretKey, ivHex);
// 设置加密后的数据到请求体
pm.request.body.raw = encryptedData;
// 可选:添加加密信息头
pm.request.headers.upsert({
key: 'X-Encrypted-IV',
value: ivHex
});
|
| 请求数据 | POST: localhost:9898/data-security/account/getInfoByWrapper
Header: X-Encrypted-ClientKey: BOv9lA7TLM358HTgsMa/0c3iPu8k+UShdw0H1iwMqqFBf+V/s7pplR7jT2cdUBYfRhj8fbeOI/dgy2/VVqG8e5qA/fDAVwKQmI0u0MuqNGoHg48UGhCbKwxzwk24cSZj0eZkO58B7v10kB1+sARE7hsSFbn+r8OAuSOwhSeoxGG8
RequestBody请求数据:
lelKWOI+fJO/6XrTnjqZqWeppGuC6zn+hK40W5pYKuv0ma/O3EFx7VXxI+geBdjV
ResponseBody: "tHgZ5ENlVhWq6QGmaaNRJy/DjU+1datQ2EiteFD9fAltwRR8EwX3gzROm1HwCa4hq8GOS+JMa64kcgrYzZ1WPRvqCw+Y6jEeOcgiNAxCAchN23Mv/dob0aeM4CwI5pzx1QGBsGJeTLle5Dv9oDkTyg=="
|
| 返回数据解密 | // 响应后脚本 - 解密SM4加密的响应数据
// 设置你的密钥和IV(实际项目中应从配置或环境变量获取)
var secretKey = "0123456789abcdeffedcba7896543210"; // 必须是16字节(128位)
function decryptData(ciphertext, key, iv) {
// 使用SM4-CBC模式解密
let decryptStr = ciphertext.replaceAll("\"", "");
// 将Base64转换为字节数组
var ciphertextBytes = base64ToBytes(decryptStr);
// 将字节数组转换为16进制字符串
var ciphertextHex = bytesToHex(ciphertextBytes);
// 使用SM4-CBC模式加密
var decryptedResult = sm4.decrypt(ciphertextHex, key, { mode: 'cbc', iv: iv })
return decryptedResult;
}
// 辅助函数:Base64转字节数组
function base64ToBytes(base64) {
var base64Chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
base64 = base64.replace(/=+$/, '');
var bytes = [];
for (var i = 0; i < base64.length; i += 4) {
var enc1 = base64Chars.indexOf(base64.charAt(i));
var enc2 = base64Chars.indexOf(base64.charAt(i + 1));
var enc3 = base64Chars.indexOf(base64.charAt(i + 2));
var enc4 = base64Chars.indexOf(base64.charAt(i + 3));
var byte1 = (enc1 << 2) \| (enc2 >> 4);
var byte2 = ((enc2 & 0x0F) << 4) \| (enc3 >> 2);
var byte3 = ((enc3 & 0x03) << 6) \| enc4;
bytes.push(byte1);
if (enc3 !== 64) bytes.push(byte2);
if (enc4 !== 64) bytes.push(byte3);
}
return bytes;
}
// 辅助函数:字节数组转16进制字符串
function bytesToHex(bytes) {
var hex = [];
for (var i = 0; i < bytes.length; i++) {
var b = bytes[i];
hex.push((b < 16 ? '0' : '') + b.toString(16));
}
return hex.join('');
}
// 获取响应数据
var responseData = pm.response.text();
const envIV = pm.response.headers.get('X-Encrypted-IV');
// 解密数据
var decryptedData = decryptData(responseData, secretKey, envIV);
// 尝试解析为JSON(如果是JSON格式)
try {
var jsonData = JSON.parse(decryptedData);
pm.response.json = function () { return jsonData; };
} catch (e) {
// 如果不是JSON,保留原始解密文本
pm.response.text = function () { return decryptedData; };
}
// 记录解密结果到控制台
console.log("解密响应:", decryptedData);
|
### 非对称加密混合会话模式【秘钥对称加密、传输数据非对称加密】: RSA、SM2、ECC(ECDH、ECDSA)、ElGamal、自定义非对称加密
#### 加解密流程(需要Redis支持)
1. 首次创建会话时传输对称密钥
客户端 → 生成对称密钥 → 用服务端公钥加密 → 发送【加密的对称密钥】→ 服务端
服务端 → 用私钥解密对称密钥 → 生成会话ID → 存储【会话ID → 对称密钥】到Redis → 返回会话ID给客户端
2. 后续请求仅携带会话ID
客户端 → 发送【会话ID + 用客户端秘钥加密的请求数据】→ 服务端
服务端 → 用会话ID从Redis获取客户端密钥 → 解密请求数据 → 处理业务 → 用客户端秘钥加密响应 → 返回客户端
#### 默认参数配置(非对称密钥对、会话有效期,会话数和限流配置)
```yaml
# 混合加密模式
csg-tsc:
rsa-key:
# 密钥有效期(小时),默认24小时
expiryHours: 24
rsa-session:
# 最大会话数,默认100000
maxCount: 100000
# 会话过期时间,单位秒,默认8小时过期
expirySeconds: 28800
# 每个IP每分钟最多允许1000次请求,默认1000
ipRateLimit: 1000
# 如果设置为 60 秒,表示统计最近 60 秒内的请求次数. 默认60
ipRateWindow: 60
```
当没有配置数据时将使用默认配置
#### 使用方法(多项目共用一个Redis,客户端编码必须配置)
* 1、项目秘钥配置【使用SM4加密传输数据,SM2传输秘钥为例】
```java
@Configuration
public class DataSecurityConfig {
@Bean
public SecretConfig secretConfig() {
return SecretConfig.builder()
.reqAlgorithm(SecretAlgorithm.SM4_CBC_PKCS7)
.requestAsymmetricMode(RequestAsymmetricMode.SM2_WITH_SESSION)
.dbSecretKey("数据存储加密秘钥") // 不使用可以不配置
// 数据存储加解密算法
.dbAlgorithm(SecretAlgorithm.PKCS7) // 不使用可以不配置
.clientCode("system") // 客户端编码
.build();
}
}
```
* 2、前端获取公钥
```html
Get: localhost:9898/data-security/api/asymmetricTSC/public-key
Response响应数据:
{
"publicKey": "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEFgFkoXDTKyP2jhigRUlrI3qO0LxZ3emioBNS8ReMYW19PMSEw+90mWmWBDcF8h0eUwDmpMWaXApfX2vRWWfwtw==",
"version": "c72255c86c5f4993b39dea9458140fd7"
}
```
* 3、前端使用公钥加密私钥
--自定义方法处理
* 4、获取请求会话
```html
Post: localhost:9898/data-security/api/asymmetricTSC/create-session
Header请求头:
X-Client-Key:BLhIkXkGvHfPaTZq8MmWXys3BVa2bznqS0j/seGtmHYSqbcU1kUKtG2RnhtXbNoq8xD+HIsImQKyqPTz8KIGiqY9gvDEPuVFxpI/lZAI2rbT3yflfgOWG7OfLRn54q0Y6zhb6vKIzWJfup5RW1RqFUiItikGkh+z9JA5PY+mo7de
X-Timestamp: 1752459639000
Response响应数据:
{
"expiresIn": 7789,
"publicKeyVersion": "c72255c86c5f4993b39dea9458140fd7",
"sessionId": "224a47ff805f41738c1f78e160c6534e"
}
```
* 5、请求数据传输用例(采用16进制的IV模式,base64的IV请参考:动态Base64编码IV,前端用ApiPost模拟)
| 步骤 | 处理方法 |
|:------:|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 参数加密 | // 设置你的密钥和IV(实际项目中应从配置或环境变量获取)
var secretKey = "0123456789abcdeffedcba7896543210"; // 必须是16字节(128位)
// 生成 16 字节随机 IV(以 WordArray 格式表示)
var iv = CryptoJS.lib.WordArray.random(16);
// 转换为十六进制字符串(可读性更好)
var ivHex = iv.toString(CryptoJS.enc.Hex);
// 请求前脚本 - SM4加密请求数据并以Base64格式输出
function encryptData(word, key, iv) {
// 如果数据是对象,转换为JSON字符串
// 使用SM4-CBC模式加密
let encryptedHex = sm4.encrypt(word, key, { mode: 'cbc', iv: iv }) // 加密,cbc 模式
// 将16进制字符串转换为字节数组
var bytes = hexToBytes(encryptedHex);
// 将字节数组转换为Base64
var encryptedBase64 = bytesToBase64(bytes);
return encryptedBase64;
}
// 辅助函数:16进制字符串转字节数组
function hexToBytes(hex) {
var bytes = [];
for (var i = 0; i < hex.length; i += 2) {
bytes.push(parseInt(hex.substr(i, 2), 16));
}
return bytes;
}
// 辅助函数:字节数组转Base64
function bytesToBase64(bytes) {
var base64Chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
var result = '';
var i = 0;
while (i < bytes.length) {
var byte1 = bytes[i++];
var byte2 = i < bytes.length ? bytes[i++] : 0;
var byte3 = i < bytes.length ? bytes[i++] : 0;
var enc1 = byte1 >> 2;
var enc2 = ((byte1 & 0x03) << 4) \| (byte2 >> 4);
var enc3 = ((byte2 & 0x0F) << 2) \| (byte3 >> 6);
var enc4 = byte3 & 0x3F;
if (i > bytes.length + 1) {
enc3 = enc4 = 64;
} else if (i > bytes.length) {
enc4 = 64;
}
result += base64Chars.charAt(enc1) + base64Chars.charAt(enc2) +
base64Chars.charAt(enc3) + base64Chars.charAt(enc4);
}
return result;
}
// 获取请求数据
var requestData = pm.request.body.raw;
let encryptedData = encryptData(requestData, secretKey, ivHex);
// 设置加密后的数据到请求体
pm.request.body.raw = encryptedData;
// 可选:添加加密信息头
pm.request.headers.upsert({
key: 'X-Encrypted-IV',
value: ivHex
});
|
| 请求数据 | POST: localhost:9898/data-security/account/getInfoByWrapper
Header: X-Encrypted-SessionId: 224a47ff805f41738c1f78e160c6534e(会话id)
RequestBody请求数据:
FzW0t8uo9sWxEgj+CBXspDBk5A0EthEvjnFT1z5ecOa1oUmsNfUQhTa3hdVQYS0W
ResponseBody: "tHgZ5ENlVhWq6QGmaaNRJy/DjU+1datQ2EiteFD9fAltwRR8EwX3gzROm1HwCa4hq8GOS+JMa64kcgrYzZ1WPRvqCw+Y6jEeOcgiNAxCAchN23Mv/dob0aeM4CwI5pzx1QGBsGJeTLle5Dv9oDkTyg=="
|
| 返回数据解密 | // 响应后脚本 - 解密SM4加密的响应数据
// 设置你的密钥和IV(实际项目中应从配置或环境变量获取)
var secretKey = "0123456789abcdeffedcba7896543210"; // 必须是16字节(128位)
function decryptData(ciphertext, key, iv) {
// 使用SM4-CBC模式解密
let decryptStr = ciphertext.replaceAll("\"", "");
// 将Base64转换为字节数组
var ciphertextBytes = base64ToBytes(decryptStr);
// 将字节数组转换为16进制字符串
var ciphertextHex = bytesToHex(ciphertextBytes);
// 使用SM4-CBC模式加密
var decryptedResult = sm4.decrypt(ciphertextHex, key, { mode: 'cbc', iv: iv })
return decryptedResult;
}
// 辅助函数:Base64转字节数组
function base64ToBytes(base64) {
var base64Chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
base64 = base64.replace(/=+$/, '');
var bytes = [];
for (var i = 0; i < base64.length; i += 4) {
var enc1 = base64Chars.indexOf(base64.charAt(i));
var enc2 = base64Chars.indexOf(base64.charAt(i + 1));
var enc3 = base64Chars.indexOf(base64.charAt(i + 2));
var enc4 = base64Chars.indexOf(base64.charAt(i + 3));
var byte1 = (enc1 << 2) \| (enc2 >> 4);
var byte2 = ((enc2 & 0x0F) << 4) \| (enc3 >> 2);
var byte3 = ((enc3 & 0x03) << 6) \| enc4;
bytes.push(byte1);
if (enc3 !== 64) bytes.push(byte2);
if (enc4 !== 64) bytes.push(byte3);
}
return bytes;
}
// 辅助函数:字节数组转16进制字符串
function bytesToHex(bytes) {
var hex = [];
for (var i = 0; i < bytes.length; i++) {
var b = bytes[i];
hex.push((b < 16 ? '0' : '') + b.toString(16));
}
return hex.join('');
}
// 获取响应数据
var responseData = pm.response.text();
const envIV = pm.response.headers.get('X-Encrypted-IV');
// 解密数据
var decryptedData = decryptData(responseData, secretKey, envIV);
// 尝试解析为JSON(如果是JSON格式)
try {
var jsonData = JSON.parse(decryptedData);
pm.response.json = function () { return jsonData; };
} catch (e) {
// 如果不是JSON,保留原始解密文本
pm.response.text = function () { return decryptedData; };
}
// 记录解密结果到控制台
console.log("解密响应:", decryptedData);
|
# 问题排查
+ Expected parsed RequestPath in request attribute "org.springframework.web.util.ServletRequestPathUtils.PATH".
修改路径解析的方式
``` yaml
spring:
mvc:
pathmatch:
matching-strategy: ant_path_matcher
```