本文主要是介绍SpringBoot实现RSA+AES自动接口解密的实战指南,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
《SpringBoot实现RSA+AES自动接口解密的实战指南》在当今数据泄露频发的网络环境中,接口安全已成为开发者不可忽视的核心议题,RSA+AES混合加密方案因其安全性高、性能优越而被广泛采用,本...
在当今数据泄露频发的网络环境中,接口安全已成为开发者不可忽视的核心议题。RSA+AES混合加密方案因其安全性高、性能优越而被广泛采用:
- RSA(非对称加密):解决密钥分发难题,适合加密小数据(如AES密钥)。
- AES(对称加密):高效加密大量数据,适合传输业务参数。
本文将深入SpringBoot框架,手把手演示如何通过自定义注解+拦截器实现接口的自动化加解密,并提供完整工具类、AOP切片代码及安全优化策略。
一、项目依赖与环境准备
1.1 Maven依赖配置
在pom.XML
中添加必要的依赖:
<dependencies> <!-- SpringBoot Web支持 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- jsON处理工具 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.83</version> </dependency> <!-- 加密算法扩展(支持BCrypt等) --> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk15on</artifactId> <version>1.70</version> </dependency> <!-- Lombok简化代码 --> <depenwww.chinasem.cndency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> </dependencies>js
1.2 密钥生成与配置
RSA密钥对生成:
// 工具类:生成RSA密钥对
public class KeyGenerator {
public static void main(String[] args) throws Exception {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(2048); // 2048位密钥长度
KeyPair keyPair = keyGen.generateKeyPair();
// 公钥(客户端使用)
String publicKeyStr = Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded());
System.out.println("Public Key:\n" + publicKeyStr);
编程
// 私钥(服务端使用)
String privateKeyStr = Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded());
System.out.println("Private Key:\n" + privateKeyStr);
}
}
配置文件中存储密钥:
# application.yml encrypt: rsa: public-key: "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA..." private-key: "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC..."
二、加密工具类实现
2.1 RSA工具类
import org.bouncycastle.jce.provider.BouncyCastleProvider; import Javax.crypto.Cipher; import java.security.*; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.Base64; public class RSAUtil { static { Security.addProvider(new BouncyCastleProvider()); // 添加BC支持 } // 使用公钥加密 public static String encrypt(String data, String publicKeyStr) throws Exception { PublicKey publicKey = getPublicKeyFromBase64(publicKeyStr); Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); cipher.init(Cipher.ENCRYPT_MODE, publicKey); return Base64.getEncoder().encodeToString(cipher.doFinal(data.getBytes())); } // 使用私钥解密 public static String decrypt(String encryptedData, String privateKeyStr) throws Exception { PrivateKey privateKey = getPrivateKeyFromBase64(privateKeyStr); Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); cipher.init(Cipher.DECRYPT_MODE, privateKey); return new String(cipher.doFinal(Base64.getDecoder().decode(encryptedData))); } // 从Base64字符串生成公钥 private static PublicKey getPublicKeyFromBase64(String keyStr) throws Exception { byte[] keyBytes = Base64.getDecoder().decode(keyStr); X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); return keyFactory.generatePublic(spec); } // 从Base64字符串生成私钥 private static PrivateKey getPrivateKeyFromBase64(String keyStr) throws Exception { byte[] keyBytes = Base64.getDecoder().decode(keyStr); PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); return keyFactory.generatePrivate(spec); } }
2.2 AES工具类
import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import java.nio.charset.StandardCharsets; import java.security.SecureRandom; import java.util.Base64; public class AESUtil { // AES加密模式:CBC + PKCS7Padding private static final String AES_MODE = "AES/CBC/PKCS7Padding"; private static final int IV_LENGTH = 16; // 初始化向量长度 // 生成随机AES密钥 public static String generateAESKey() throws Exception { byte[] key = new byte[16]; // 128位密钥 new SecureRandom().nextBytes(key); return Base64.getEncoder().encodeToString(ke编程y); } // AES加密 public static String encrypt(String data, String aesKey) throws Exception { byte[] keyBytes = Base64.getDecoder().decode(aesKey); SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES"); byte[] iv = new byte[IV_LENGTH]; new SecureRandom().nextBytes(iv); IvParameterSpec ivSpec = new IvParameterSpec(iv); Cipher cipher = Cipher.getInstance(AES_MODE); cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec); byte[] encryptedBytes = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8)); // 将IV和密文合并返回 byte[] result = new byte[iv.length + encryptedBytes.length]; System.arraycopy(iv, 0, result, 0, iv.length); System.arraycopy(encryptedBytes, 0, result, iv.length, encryptedBytes.length); return Base64.getEncoder().encodeToString(result); } // AES解密 public static String decrypt(String encryptedData, String aesKey) throws Exception { byte[] data = Base64.getDecoder().decode(encryptedData); byte[] iv = new byte[IV_LENGTH]; byte[] encryptedBytes = new byte[data.length - IV_LENGTH]; System.arraycopy(data, 0, iv, 0, IV_LENGTH); System.arraycopy(data, IV_LENGTH, encryptedBytes, 0, encryptedBytes.length); SecretKeySpec keySpec = new SecretKeySpec(Base64.getDecoder().decode(aesKey), "AES"); IvParameterSpec ivSpec = new IvParameterSpec(iv); Cipher cipher = Cipher.getInstjavascriptance(AES_MODE); cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec); return new String(cipher.doFinal(encryptedBytes), StandardCharsets.UTF_8); } }
三、自定义注解与AOP切面
3.1 自定义解密注解 @RequestRSA
import java.lang.annotation.*; @Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface RequestRSA { // 标记需要解密的接口 }
3.2 AOP切面实现自动解密
import com.alibaba.fastjson.JSONObject; import org.ASPectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.RequestBody; import javax.servlet.http.HttpServletRequest; import java.io.BufferedReader; import java.io.InputStreamReader; import java.lang.reflect.Method; import java.lang.reflect.Parameter; /** * RSA+AES接口解密切面 */ @Aspect @Component @Order(1) public class RequestRSAAspect { @Value("${encrypt.rsa.private-key}") private String privateKey; /** * 拦截带有@RequestRSA注解的方法 */ @Around("@annotation(requestRSA) || @within(requestRSA)") public Object decryptRequest(ProceedingJoinPoint joinPoint, RequestRSA requestRSA) throws Throwable { // 获取请求体 HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); String body = getRequestBody(request); // 解析加密参数 JSONObject encryptedJson = JSONObject.parseobject(body); String sym = encryptedJson.getString("sym"); // RSA加密的AES密钥 String asy = encryptedJson.getString("asy"); // AES加密的业务数据 // RSA解密获取AES密钥 String aesKey = RSAUtil.decrypt(sym, privateKey); // AES解密业务数据 String decryptedData = AESUtil.decrypt(asy, aesKey); // 将解密后的数据注入方法参数 Object[] args = injectDecryptedData(joinPoint, decryptedData); return joinPoint.proceed(args); } /** * 读取请求体内容 */ private String getRequestBody(HttpServletRequest request) throws Exception { StringBuilder sb = new StringBuilder(); BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream())); String line; while ((line = reader.readLine()) != null) { sb.append(line); } return sb.toString(); } /** * 将解密后的数据注入方法参数 */ private Object[] injectDecryptedData(ProceedingJoinPoint joinPoint, String decryptedData) throws Exception { MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); Parameter[] parameters = method.getParameters(); Object[] args = joinPoint.getArgs(); for (int i = 0; i < parameters.length; i++) { if (parameters[i].isAnnotationPresent(RequestBody.class)) { // 将解密后的JSON字符串反序列化为目标对象 args[i] = JSONObject.parseObject(decryptedData, parameters[i].getParameterizedType()); } } return args; } }
四、客户端加密逻辑实现
4.1 客户端加密流程
public class ClientEncryption { public static void main(String[] args) throws Exception { // 1. 随机生成AES密钥和IV String aesKey = AESUtil.generateAESKey(); String aesIV = AESUtil.generateAESKey(); // 实际应使用SecureRandom生成IV // 2. 构造请求参数 JSONObject requestData = new JSONObject(); requestData.put("username", "user123"); requestData.put("password", "securePass"); // 3. AES加密业务数据 String asy = AESUtil.encrypt(requestData.toJSONString(), aesKey); // 4. 构造AES密钥信息 JSONObject aesInfo = new JSONObject(); aesInfo.put("key", aesKey); aesInfo.put("keyVI", aesIV); aesInfo.put("time", System.currentTimeMillis()); // 5. RSA加密AES密钥信息 String sym = RSAUtil.encrypt(aesInfo.toJSONString(), "服务器公钥"); // 6. 构造最终请求体 JSONObject finalRequest = new JSONObject(); finalRequest.put("sym", sym); finalRequest.put("asy", asy); System.out.println("加密后请求体:\n" + finalRequest.toJSONString()); } }
五、服务器端接口示例
5.1 带解密注解的接口
@RestController @RequestMapping("/api") public class SecureController { @PostMapping("/login") @RequestRSA // 标记需要解密 public Response login(@RequestBody LoginRequest request) { // 直接使用解密后的参数 return new Response("登录成功", request.getUsername()); } } // 请求参数类 @Data public class LoginRequest { private String username; private String password; }
六、安全优化与最佳实践
6.1 密钥管理策略
- 私钥存储:使用配置中心(如Nacos)或密钥管理服务(如AWS KMS)。
- 公钥分发:通过HTTPS协议分发,避免中间人攻击。
- 定期轮换:每30天更新一次RSA密钥对。
6.2 时间戳防重放攻击
在AOP切面中添加时间戳校验:
private void validateTimestamp(JSONObject aesInfo) { long requestTime = aesInfo.getLong("time"); long currentTime = System.currentTimeMillis(); if (Math.abs(currentTime - requestTime) > 60000) { // 允许1分钟内 throw new RuntimeException("请求超时,请重试"); } }
6.3 性能优化建议
- 缓存公钥/私钥对象:避免重复解析Base64字符串。
- 异步解密:对高并发接口采用线程池异步处理。
- 压缩数据:对加密后的数据进行GZIP压缩减少传输体积。
七、完整调用流程图解
客户端流程: [生成AES密钥] → [AES加密数据] → [构造AES信息] → [RSA加密AES信息] → [发送请求] 服务端流程: [接收请求] → [AOP切面拦截] → [RSA解密AES密钥] → [AES解密业务数据] → [注入参数执行接口]
八、 构建高安全接口的核心要点
模块 | 关键点 | 注意事项 |
---|---|---|
密钥管理 | RSA公私钥分离存储,AES密钥动态生成 | 私钥需加密存储,定期轮换 |
加密流程 | RSA加密AES密钥,AES加密业务数据 | 确保IV随机性,避免重复使用 |
AOP切面设计 | 自动拦截、解密、参数注入 | 处理异常情况(如密钥错误、时间戳过期) |
安全防护 | 时间戳防重放、HTTPS传输、数据完整性校验 | 避免硬编码密钥,使用配置中心 |
九、 工具类与依赖说明
- Bouncy Castle:提供扩展的加密算法支持(如PKCS7Padding)。
- FastJSON:高效JSON序列化/反序列化。
- Lombok:简化POJO类的编写(如
@Data
注解)。
以上就是SpringBoot实现RSA+AES自动接口解密的实战指南的详细内容,更多关于SpringBoot RSA AES接口解密的资料请关注China编程(www.chinasem.cn)其它相关文章!
这篇关于SpringBoot实现RSA+AES自动接口解密的实战指南的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!