当前位置: 代码网 > it编程>编程语言>Java > SpringBoot实现RSA+AES自动接口解密的实战指南

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

2025年08月03日 Java 我要评论
在当今数据泄露频发的网络环境中,接口安全已成为开发者不可忽视的核心议题。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简化代码 -->
    <dependency>
        <groupid>org.projectlombok</groupid>
        <artifactid>lombok</artifactid>
        <optional>true</optional>
    </dependency>
</dependencies>

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(key);
    }

    // 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.getinstance(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接口解密的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com