惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Martin Fowler
Martin Fowler
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
T
Troy Hunt's Blog
Latest news
Latest news
Vercel News
Vercel News
S
SegmentFault 最新的问题
V
Vulnerabilities – Threatpost
博客园 - Franky
P
Privacy International News Feed
A
Arctic Wolf
T
The Blog of Author Tim Ferriss
S
Schneier on Security
T
The Exploit Database - CXSecurity.com
P
Palo Alto Networks Blog
T
Tor Project blog
Jina AI
Jina AI
GbyAI
GbyAI
The Hacker News
The Hacker News
博客园 - 叶小钗
Google DeepMind News
Google DeepMind News
T
Threatpost
C
CERT Recently Published Vulnerability Notes
P
Proofpoint News Feed
Scott Helme
Scott Helme
WordPress大学
WordPress大学
www.infosecurity-magazine.com
www.infosecurity-magazine.com
Microsoft Azure Blog
Microsoft Azure Blog
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
博客园 - 司徒正美
A
About on SuperTechFans
Recorded Future
Recorded Future
爱范儿
爱范儿
L
LangChain Blog
V
V2EX
C
Cybersecurity and Infrastructure Security Agency CISA
The Cloudflare Blog
阮一峰的网络日志
阮一峰的网络日志
K
Kaspersky official blog
Webroot Blog
Webroot Blog
Security Archives - TechRepublic
Security Archives - TechRepublic
D
DataBreaches.Net
宝玉的分享
宝玉的分享
Google Online Security Blog
Google Online Security Blog
C
Cisco Blogs
L
Lohrmann on Cybersecurity
Help Net Security
Help Net Security
AWS News Blog
AWS News Blog
M
MIT News - Artificial intelligence
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
G
GRAHAM CLULEY

李锋镝的博客

LiteLLM 本地代理搭建 Claude-HUD 使用文档 Kratos+ —— Kratos 主题二次开发记录 译文:如何将单体应用拆解为微服务 codebase-memory-mcp 极简完整使用指南 Claude Haiku 4.5、Claude Sonnet 4.6、Claude Opus 4.7 区别以及各自的新特性 SchedulingConfigurer详解 踩坑60+次后,我终于搞懂 Claude Skill 怎么写才会真的触发 Everything Claude Code 详细使用文档 配置Jackson使用字段而不是getter/setter来序列化和反序列化 这个域名注册整整十年了,十年时间,真快啊 Claude Code全维度实战指南:从入门到精通,解锁AI编程新范式 Apollo配置中心中的protalDB的作用是什么 org.apache.ibatis.plugin.Interceptor类详细介绍及使用 岁末 Excel2016右键新建工作表,打开时提示“因为文件格式或文件扩展名无效。请确定文件未损坏,并且文件扩展名与文件的格式匹配。”的解决办法 wordpress增加说说功能 Java 为什么有这么多 “O”? 别再背线程池的七大参数了,现在面试官都这么问 2024年11月1号 农历十月初一 我的第一个WordPress插件:Dylan Custom Plugin上线了 推荐一款比较养眼的Xshell配色方案 hnswlib installation failed 开工啦~ 阳了... MybatisCodeHelperPro激活 @Async注解的坑 新买的笔记本发货啦…… 这个中秋节感觉过的好累啊 IDEA下载源码报:Cannot connect to the Maven process. Try again later. RocketMQ的push消费方式实现详解 看病难~取药难~~ 笑死、腹肌……根本不可能有腹肌的~~ 居家办公了~ C# 11 的这个新特性,我愿称之最强! IntelliJ IDEA 2020.3.x永久白嫖(Windows/Mac) IDEA无限试用方法【2020.3最新亲测有效】 SpringBoot使用注解的方式构建Elasticsearch查询语句,实现多条件的复杂查询 UUID太长怎么办?快来试试NanoId 忽然发现,在校大学生可以免费领一年有道云笔记会员~ 醒醒~补个税了 使用itext和freemarker来根据Html模板生成PDF文件,加水印、印章 来来来,用python画一个冰墩墩儿 SpringBoot整合GraphQL入门教程 办理居住证困难重重啊! 妈呀,昨天晚上睡觉做了一晚上的梦,可累死我了 感觉Typecho很简洁啊…… WordPress的自动更新好烦啊 BeanCopier工具类(性能优化工具类) 内存屏障浅析 居住证可算是申请通过了…… 试了下壁挂炉供暖 关于重阳节 居住证签注... Spring Boot 2.x使用PostgreSQL数据库 十一节后开工头一天,修了个耳机…… 玉楼春·尊前拟把归期说 nginx反向代理配置去除前缀 1931→2021! Navicat Premium数据库账号密码解密 百度的索引量数据现在有点儿太夸张了吧? 哇塞~这个小姐姐实在太惊艳了…… 关于8月29号下午博客故障的一些记录 如何形象的描述反应式编程中的背压(Backpressure)机制? 基于Java8的Either类 海琴烟~~~ JMX监控权限认证配置 IntelliJ IDEA 2019.3.3 永久激活 破解[Windows] SpringBoot整合Elasticsearch详细步骤以及代码示例(附源码) SpringBoot整合Elasticsearch游标查询(scroll) GitLab创建新项目,初次提交命令和流程 吐槽下Google浏览器~ 从零搭建Spring Cloud Gateway网关(一) 从零搭建Spring Cloud Gateway网关(二)—— 打印请求响应日志 博客有logo啦 你的答案 数据库事务的一点简单总结 Spring Boot发展史(Spring Boot介绍) 【漫画】戏说外行对程序员的误会有多深 【收藏】从面试官角度观察到的程序员技能瓶颈,同时给出突破瓶颈的建议 Git中.gitignore文件不起作用的解决办法 背影 - 朱自清 jmap命令(jdk1.8) 彻底搞懂mysql日志系统binlog,redolog,undolog 出院了~~~ linux中ftp查看不到文件列表的问题 PHP版本怎么更新啊…… 成语接龙 StarUML4.0破解文件 Java SPI详解 WordPress评论框增加自定义表情 因在公司上不正经网站,我没过试用期… 优化了MYSQL大量写入问题,老板奖励了1000块给我 不慌不忙的坚强(林徽因39段最美文字!) ConcurrentHashMap常用方法源码解析(jdk1.8) 我是如何失去团队掌控的? HBASE填坑日志 关闭apache httpclient4.5 DEBUG日志 使用OpenShift搭建k8s集群 SonarQube Scanner的配置与使用简介
SpringBoot 实现 RSA+AES 自动接口解密
李锋镝 · 2025-07-11 · via 李锋镝的博客

一、背景

在网络传输敏感数据时,接口加密是保障安全的核心手段。下面就说一说如何在 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/article/4428