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

推荐订阅源

N
Netflix TechBlog - Medium
IT之家
IT之家
博客园_首页
Hugging Face - Blog
Hugging Face - Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
美团技术团队
小众软件
小众软件
博客园 - 叶小钗
WordPress大学
WordPress大学
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园 - 三生石上(FineUI控件)
罗磊的独立博客
博客园 - Franky
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Last Week in AI
Last Week in AI
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
有赞技术团队
有赞技术团队
T
Tailwind CSS Blog
宝玉的分享
宝玉的分享
博客园 - 【当耐特】
月光博客
月光博客
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
酷 壳 – CoolShell
酷 壳 – CoolShell
人人都是产品经理
人人都是产品经理

李锋镝的博客

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.
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