李锋镝的博客

  • 首页
  • 时间轴
  • 留言
  • 插件
  • 左邻右舍
  • 关于我
    • 关于我
    • 另一个网站
  • 知识库
  • 赞助
Destiny
自是人生长恨水长东
  1. 首页
  2. 原创
  3. 正文

SpringBoot 实现 RSA+AES 自动接口解密

2025年5月26日 31点热度 0人点赞 0条评论

一、背景

在网络传输敏感数据时,接口加密是保障安全的核心手段。下面就说一说如何在 SpringBoot 中实现 RSA+AES 混合加密方案,同时结合两种算法的优势,确保数据传输的安全性与高效性。

二、加密方案优势

算法 特点 适用场景
RSA 非对称加密,安全性高,但加密速度慢,适合加密少量数据(如密钥)。 加密 AES 密钥
AES 对称加密,速度快,适合大量数据加密,但密钥分发困难。 加密实际传输数据
混合方案 RSA 加密 AES 密钥 + AES 加密业务数据,兼顾安全与性能。 敏感数据接口通信

三、实现原理

  1. 客户端流程:

    • 生成随机 AES 密钥。
    • 用 RSA 公钥 加密 AES 密钥。
    • 用 AES 密钥加密业务数据,附带初始化向量(IV)和时间戳。
    • 发送加密后的 AES 密钥、加密数据、IV、时间戳至服务端。
  2. 服务端流程:

    • 用 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),确保数据完整性。
除非注明,否则均为李锋镝的博客原创文章,转载必须以链接形式标明本文链接

本文链接:https://www.lifengdi.com/archives/article/4428

相关文章

  • @Valid 和 @Validated 的区别
  • SpringBoot常用注解
  • CompletableFuture使用详解
  • SpringBoot 中内置的 49 个常用工具类
  • SpringBoot 实现接口防刷的 5 种实现方案
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可
标签: AES JAVA RSA SpringBoot 加解密 安全 对称加密 非对称加密
最后更新:2025年5月26日

李锋镝

既然选择了远方,便只顾风雨兼程。

打赏 点赞
< 上一篇
下一篇 >

文章评论

1 2 3 4 5 6 7 8 9 11 12 13 14 15 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 46 47 48 49 50 51 52 53 54 55 57 58 60 61 62 63 64 65 66 67 69 72 74 76 77 78 79 80 81 82 85 86 87 90 92 93 94 95 96 97 98 99
取消回复

遥知兄弟登高处,遍插茱萸少一人。

最新 热点 随机
最新 热点 随机
ReentrantLock深度解析 RedisTemplate和Redisson的区别 SpringBoot常用注解 CompletableFuture使用详解 金融级JVM深度调优实战的经验和技巧 SpringBoot 实现接口防刷的 5 种实现方案
玩博客的人是不是越来越少了?2024年11月1号 农历十月初一准备入手个亚太的ECS,友友们有什么建议吗?别再背线程池的七大参数了,现在面试官都这么问@Valid 和 @Validated 的区别SpringBoot 实现接口防刷的 5 种实现方案
CentOS安装docker 【三国轶闻】张飞多次挑衅吕布却安然无事,吕布到底害怕张飞什么? 分布式事务的 N 种实现 架构师究竟比高级开发厉害在哪? 如何高效的学习技术? JVM安全点介绍
标签聚合
文学 SpringBoot 教程 JAVA ElasticSearch Spring Redis 多线程 日常 IDEA 面试 docker 分布式 MySQL 设计模式 K8s JVM 架构 SQL 数据库
友情链接
  • i架构
  • LyShark - 孤风洗剑
  • 临窗旋墨
  • 博友圈
  • 博客录
  • 博客星球
  • 哥斯拉
  • 志文工作室
  • 搬砖日记
  • 旋律的博客
  • 旧时繁华
  • 林羽凡
  • 知向前端
  • 集博栈
  • 韩小韩博客

COPYRIGHT © 2025 lifengdi.com. ALL RIGHTS RESERVED.

Theme Kratos Made By Dylan

津ICP备2024022503号-3