SpringBoot实现RSA+AES自动接口解密的实战指南

2025-08-03 21:50

本文主要是介绍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自动接口解密的实战指南的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1155586

相关文章

使用Redis快速实现共享Session登录的详细步骤

《使用Redis快速实现共享Session登录的详细步骤》在Web开发中,Session通常用于存储用户的会话信息,允许用户在多个页面之间保持登录状态,Redis是一个开源的高性能键值数据库,广泛用于... 目录前言实现原理:步骤:使用Redis实现共享Session登录1. 引入Redis依赖2. 配置R

使用Python的requests库调用API接口的详细步骤

《使用Python的requests库调用API接口的详细步骤》使用Python的requests库调用API接口是开发中最常用的方式之一,它简化了HTTP请求的处理流程,以下是详细步骤和实战示例,涵... 目录一、准备工作:安装 requests 库二、基本调用流程(以 RESTful API 为例)1.

Oracle迁移PostgreSQL隐式类型转换配置指南

《Oracle迁移PostgreSQL隐式类型转换配置指南》Oracle迁移PostgreSQL时因类型差异易引发错误,需通过显式/隐式类型转换、转换关系管理及冲突处理解决,并配合验证测试确保数据一致... 目录一、问题背景二、解决方案1. 显式类型转换2. 隐式转换配置三、维护操作1. 转换关系管理2.

Nginx进行平滑升级的实战指南(不中断服务版本更新)

《Nginx进行平滑升级的实战指南(不中断服务版本更新)》Nginx的平滑升级(也称为热升级)是一种在不停止服务的情况下更新Nginx版本或添加模块的方法,这种升级方式确保了服务的高可用性,避免了因升... 目录一.下载并编译新版Nginx1.下载解压2.编译二.替换可执行文件,并平滑升级1.替换可执行文件

在Java中实现线程之间的数据共享的几种方式总结

《在Java中实现线程之间的数据共享的几种方式总结》在Java中实现线程间数据共享是并发编程的核心需求,但需要谨慎处理同步问题以避免竞态条件,本文通过代码示例给大家介绍了几种主要实现方式及其最佳实践,... 目录1. 共享变量与同步机制2. 轻量级通信机制3. 线程安全容器4. 线程局部变量(ThreadL

Python调用LibreOffice处理自动化文档的完整指南

《Python调用LibreOffice处理自动化文档的完整指南》在数字化转型的浪潮中,文档处理自动化已成为提升效率的关键,LibreOffice作为开源办公软件的佼佼者,其命令行功能结合Python... 目录引言一、环境搭建:三步构建自动化基石1. 安装LibreOffice与python2. 验证安装

python使用Akshare与Streamlit实现股票估值分析教程(图文代码)

《python使用Akshare与Streamlit实现股票估值分析教程(图文代码)》入职测试中的一道题,要求:从Akshare下载某一个股票近十年的财务报表包括,资产负债表,利润表,现金流量表,保存... 目录一、前言二、核心知识点梳理1、Akshare数据获取2、Pandas数据处理3、Matplotl

分布式锁在Spring Boot应用中的实现过程

《分布式锁在SpringBoot应用中的实现过程》文章介绍在SpringBoot中通过自定义Lock注解、LockAspect切面和RedisLockUtils工具类实现分布式锁,确保多实例并发操作... 目录Lock注解LockASPect切面RedisLockUtils工具类总结在现代微服务架构中,分布

Java使用Thumbnailator库实现图片处理与压缩功能

《Java使用Thumbnailator库实现图片处理与压缩功能》Thumbnailator是高性能Java图像处理库,支持缩放、旋转、水印添加、裁剪及格式转换,提供易用API和性能优化,适合Web应... 目录1. 图片处理库Thumbnailator介绍2. 基本和指定大小图片缩放功能2.1 图片缩放的

精选20个好玩又实用的的Python实战项目(有图文代码)

《精选20个好玩又实用的的Python实战项目(有图文代码)》文章介绍了20个实用Python项目,涵盖游戏开发、工具应用、图像处理、机器学习等,使用Tkinter、PIL、OpenCV、Kivy等库... 目录① 猜字游戏② 闹钟③ 骰子模拟器④ 二维码⑤ 语言检测⑥ 加密和解密⑦ URL缩短⑧ 音乐播放