本文档描述SVT后端API加密的实际实现,基于实际代码分析。
- 算法: AES-256-CBC
- 密钥长度: 256位 (32字节)
- IV: 128位 (16字节),每次随机生成
- 填充: PKCS5Padding
- 编码: Base64
- 安全: 使用SecureRandom生成随机IV
- 使用
AESCryptoFilter自动处理加解密 - 对业务代码透明,无需手动处理
- 支持开发/生产环境切换
- 数据大小限制:10MB
- 时间戳验证防重放攻击
位置:com.seventeen.svt.common.util.AESUtils
主要方法:
encrypt(String plainText, String ivString)- 使用指定IV加密数据decrypt(String encryptedData, String ivString)- 使用指定IV解密数据encryptWithIV(String plainText)- 自动生成IV并加密generateIV()- 生成随机IVisAESEnabled()- 检查是否启用加密validateKey()- 验证密钥有效性encryptForAPI(String jsonData)- API专用加密方法decryptFromAPI(Map<String, Object> encryptedData)- API专用解密方法
特性:
- 自动验证密钥长度(必须32字节)
- 支持数据大小检查
- 完整的异常处理
- 详细的日志记录
- 时间戳容差验证
位置:com.seventeen.svt.common.filter.AESCryptoFilter
功能:
- 自动解密请求体(POST/PUT/PATCH)
- 自动加密响应体
- 对GET请求和文件上传不处理
- 支持路径排除配置
位置:com.seventeen.svt.common.config.AESConfig
管理加密相关配置:
- 启用/禁用开关
- 密钥管理(Base64编码)
- 排除路径配置
- 数据大小限制设置
- 时间戳容差配置
- 调试模式开关
{
"encrypted": true,
"data": "Base64编码的密文",
"iv": "Base64编码的IV",
"timestamp": 1735804800000,
"version": "1.0"
}字段说明:
encrypted: 标识数据已加密(固定为true)data: AES-256-CBC加密后的Base64编码密文iv: 随机生成的16字节初始化向量(Base64编码)timestamp: Unix时间戳(防重放攻击)version: 格式版本号(当前为"1.0")
- 默认容差:10分钟
- 超出容差的请求在生产环境会被拒绝
- 调试模式下只记录警告不阻止
- 时间差计算:
Math.abs(currentTime - timestamp)
svt:
security:
aes:
key: ${SVT_AES_KEY} # 从环境变量读取(Base64编码的32字节密钥)
enabled: true # 是否启用加密
max-data-size: 10485760 # 最大数据大小(10MB)
timestamp-tolerance: 600000 # 时间戳容差(10分钟)
debug: false # 调试模式开关# 设置AES密钥(Base64编码的32字节密钥)
export SVT_AES_KEY=your_base64_encoded_32_byte_key_here
# 生成密钥示例(Linux/Mac)
openssl rand -base64 32
# 生成密钥示例(Windows PowerShell)
[System.Convert]::ToBase64String((1..32 | ForEach-Object { Get-Random -Maximum 256 }))- 必须是Base64编码格式
- 解码后长度必须是32字节(AES-256)
- 建议使用强随机生成器生成
- 生产环境定期轮换
@PostMapping("/api/user/create")
public Result<User> createUser(@RequestBody UserDTO userDTO) {
// 请求体已自动解密
User user = userService.create(userDTO);
return Result.success(user); // 响应会自动加密
}@Autowired
private AESUtils aesUtils;
if (aesUtils.isAESEnabled()) {
// 加密已启用
boolean keyValid = aesUtils.validateKey();
if (keyValid) {
log.info("AES加密已启用且密钥有效");
}
}@Autowired
private AESUtils aesUtils;
// 加密JSON数据为API格式
String jsonData = "{\"message\":\"Hello World\"}";
Map<String, Object> encrypted = aesUtils.encryptForAPI(jsonData);
// 解密API格式数据
String decrypted = aesUtils.decryptFromAPI(encrypted);
// 自定义IV加密
String iv = aesUtils.generateIV();
String encryptedData = aesUtils.encrypt("plaintext", iv);
String decryptedData = aesUtils.decrypt(encryptedData, iv);try {
Map<String, Object> result = aesUtils.encryptForAPI(data);
return Result.success(result);
} catch (BusinessException e) {
log.error("加密失败: {}", e.getMessage());
return Result.error("数据处理失败");
}- 使用环境变量管理密钥,严禁硬编码
- 密钥必须是Base64编码的32字节随机数据
- 生产环境定期轮换密钥
- 密钥丢失将导致所有加密数据无法解密
- 大文件传输建议使用其他方式(如直接文件传输)
- 数据大小限制10MB,可通过配置调整
- 开发环境可关闭加密提升调试效率
- 加密解密过程会增加CPU开销
- GET请求不加密(查询参数明文传输)
- 文件上传接口自动排除
- 支持明文降级(调试模式)
- 老版本客户端需要升级支持加密格式
-
密钥错误
- 检查环境变量
SVT_AES_KEY是否正确设置 - 验证密钥是否为有效的Base64编码
- 确认解码后长度为32字节
- 检查环境变量
-
时间戳错误
- 检查客户端与服务器时间同步
- 确认时间戳容差配置合理
- 调试模式下查看详细日志
-
数据大小超限
- 检查数据是否超过配置的最大大小
- 考虑数据分片或压缩
- 调整配置参数
- 监控加密失败率
- 统计加密性能指标
- 记录异常解密尝试
- 定期检查密钥有效期