一、背景
在网络传输敏感数据时,接口加密是保障安全的核心手段。下面就说一说如何在 SpringBoot 中实现 RSA+AES 混合加密方案,同时结合两种算法的优势,确保数据传输的安全性与高效性。
二、加密方案优势
算法 | 特点 | 适用场景 |
---|---|---|
RSA | 非对称加密,安全性高,但加密速度慢,适合加密少量数据(如密钥)。 | 加密 AES 密钥 |
AES | 对称加密,速度快,适合大量数据加密,但密钥分发困难。 | 加密实际传输数据 |
混合方案 | RSA 加密 AES 密钥 + AES 加密业务数据,兼顾安全与性能。 | 敏感数据接口通信 |
三、实现原理
-
客户端流程:
- 生成随机 AES 密钥。
- 用 RSA 公钥 加密 AES 密钥。
- 用 AES 密钥加密业务数据,附带初始化向量(IV)和时间戳。
- 发送加密后的 AES 密钥、加密数据、IV、时间戳至服务端。
-
服务端流程:
- 用 RSA 私钥 解密获取 AES 密钥。
- 用 AES 密钥解密业务数据,验证时间戳防重放攻击。
四、项目依赖(pom.xml
)
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.78</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.68</version>
</dependency>
</dependencies>
五、核心代码实现
1. 加密工具类(EncryptionUtils
)
package com.example.secureapi.utils;
// 省略导入包
public class EncryptionUtils {
static { Security.addProvider(new BouncyCastleProvider()); }
private static final String AES_ALGORITHM = "AES/CBC/PKCS7Padding";
private static final String RSA_ALGORITHM = "RSA/ECB/PKCS1Padding";
// 生成 RSA 密钥对
public static KeyPair generateRSAKeyPair() throws Exception {
KeyPairGenerator.getInstance("RSA").initialize(2048);
return keyPairGenerator.generateKeyPair();
}
// RSA 加密/解密
public static String encryptWithRSA(String data, PublicKey publicKey) throws Exception {
Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return Base64.getEncoder().encodeToString(cipher.doFinal(data.getBytes()));
}
public static String decryptWithRSA(String encryptedData, PrivateKey privateKey) throws Exception {
// 解密逻辑类似加密,使用私钥初始化Cipher
}
// AES 加密/解密(需初始化向量 IV)
public static String encryptWithAES(String data, SecretKey secretKey, byte[] iv) throws Exception {
Cipher cipher = Cipher.getInstance(AES_ALGORITHM, "BC");
cipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(iv));
return Base64.getEncoder().encodeToString(cipher.doFinal(data.getBytes()));
}
public static String decryptWithAES(String encryptedData, SecretKey secretKey, byte[] iv) throws Exception {
// 解密逻辑类似加密,使用 DECRYPT_MODE
}
// 生成随机 AES 密钥和 IV
public static SecretKey generateAESKey() throws Exception {
KeyGenerator.getInstance("AES").init(256);
return keyGen.generateKey();
}
public static byte[] generateIV() {
byte[] iv = new byte[16]; new SecureRandom().nextBytes(iv); return iv;
}
}
2. 请求包装类(EncryptedRequest
)
package com.example.secureapi.model;
import lombok.Data;
@Data
public class EncryptedRequest {
private String encryptedKey; // RSA 加密后的 AES 密钥
private String iv; // Base64 编码的 AES 初始化向量
private String encryptedData; // AES 加密后的业务数据
private Long timestamp; // 时间戳(防重放攻击)
private String signature; // 签名(防篡改)
}
3. 解密拦截器(DecryptInterceptor
)
package com.example.secureapi.interceptor;
// 省略导入包
@Slf4j
@Component
public class DecryptInterceptor implements HandlerInterceptor {
@Value("${security.rsa.private-key}") private String rsaPrivateKeyStr;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (!(handler instanceof HandlerMethod)) return true;
HandlerMethod handlerMethod = (HandlerMethod) handler;
Decrypt decryptAnnotation = handlerMethod.getMethodAnnotation(Decrypt.class);
if (decryptAnnotation == null) {
decryptAnnotation = handlerMethod.getBeanType().getAnnotation(Decrypt.class);
}
if (decryptAnnotation != null) {
// 解析请求体
String requestBody = request.getReader().lines().collect(Collectors.joining());
EncryptedRequest encryptedReq = JSON.parseObject(requestBody, EncryptedRequest.class);
// 解密 AES 密钥
PrivateKey rsaPrivateKey = EncryptionUtils.stringToRSAPrivateKey(rsaPrivateKeyStr);
String aesKeyStr = EncryptionUtils.decryptWithRSA(encryptedReq.getEncryptedKey(), rsaPrivateKey);
SecretKey aesKey = EncryptionUtils.stringToAESKey(aesKeyStr);
// 解密业务数据
byte[] iv = Base64.getDecoder().decode(encryptedReq.getIv());
String decryptedData = EncryptionUtils.decryptWithAES(encryptedReq.getEncryptedData(), aesKey, iv);
// 防重放攻击检查
if (encryptedReq.getTimestamp() != null &&
Math.abs(System.currentTimeMillis() - encryptedReq.getTimestamp()) > 300000) {
response.setStatus(403);
response.getWriter().write("{code:403,message:请求已过期}");
return false;
}
// 包装请求体为解密后的数据
request.setAttribute(DECRYPTED_DATA, decryptedData);
return wrapRequest(request, decryptedData);
}
return true;
}
// 自定义请求包装类,替换原始请求体
private static class DecryptedRequestWrapper extends HttpServletRequestWrapper {
private final String decryptedData;
public DecryptedRequestWrapper(HttpServletRequest request, String decryptedData) {
super(request);
this.decryptedData = decryptedData;
}
// 重写 getReader() 和 getInputStream() 方法,返回解密后的数据
}
}
4. 解密注解(@Decrypt
)
package com.example.secureapi.annotation;
import java.lang.annotation.*;
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Decrypt {
boolean checkTimestamp() default true; // 是否检查时间戳
boolean verifySignature() default false; // 是否验证签名
}
5. 拦截器配置(WebMvcConfig
)
package com.example.secureapi.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Autowired private DecryptInterceptor decryptInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(decryptInterceptor).addPathPatterns(/api/**);
}
}
六、使用方式
在需要解密的控制器或方法上添加 @Decrypt
注解:
@RestController
@RequestMapping(/api)
@Decrypt // 类级别注解,作用于所有方法
public class SecureController {
@PostMapping(/data)
public String processData(@RequestBody String decryptedData) {
// 直接处理解密后的明文数据
return 处理结果: + decryptedData;
}
}
七、总结
- 优势:RSA+AES 混合加密结合了非对称加密的安全性与对称加密的高效性,适用于敏感数据传输场景。
- 关键点:通过拦截器自动解密请求体,利用注解灵活控制需要加密的接口,同时支持时间戳防重放和签名防篡改。
- 扩展:可进一步添加签名验证(如 HMAC-SHA256),确保数据完整性。
除非注明,否则均为李锋镝的博客原创文章,转载必须以链接形式标明本文链接
文章评论