相关文章推荐
考研的投影仪  ·  perl 二维数组 - to be ...·  2 月前    · 
还单身的熊猫  ·  oracle ...·  10 月前    · 

1.最近要做一个安全性稍微高一点的项目,首先就想到了要对参数加密,和采用https协议.
2.以前对加密这块不了解,查阅了很多资料,加密方式很多种,但是大概区分两种,一个就是对称加密(DES,3DES,AES,IDEA等),另外一个就是非对称加密(RSA,Elgamal,背包算法,Rabin,D-H等)

3.这两种区别还是有的,粗浅的说:
(1)对称加密方式效率高,但是有泄露风险
(2)非对称加密方式效率比对称加密方式效率低,但是基本上没有泄露风险

4.如果想了解加密的,请先看我整理的另外一篇文章: https://blog.csdn.net/baidu_38990811/article/details/83386312

使用对称加密方式(AES)实践:

1.创建spring boot项目,导入相关依赖
2.编写加密工具类
3.编写自定义注解(让加解密细粒度)
4.编写自定义DecodeRequestAdvice和EncodeResponseBodyAdvice
5.创建controller
6.创建jsp或者html,引入js(加密和解密的通用js)

ps:因为这里没https证书,所有使用http, 考虑到前后端分离,使用json来传递数据

第一步: 略,不会的请自行百度spring boot项目如何创建!
第二步:

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.SecretKeySpec;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.util.JSONPObject;
import org.apache.commons.codec.binary.Base64;
import java.util.HashMap;
import java.util.Map;
 * 前后端数据传输加密工具类
 * @author monkey
public class AesEncryptUtils {
    //可配置到Constant中,并读取配置文件注入,16位,自己定义
    private static final String KEY = "xxxxxxxxxxxxxxxx";
    //参数分别代表 算法名称/加密模式/数据填充方式
    private static final String ALGORITHMSTR = "AES/ECB/PKCS5Padding";
     * @param content 加密的字符串
     * @param encryptKey key值
     * @return
     * @throws Exception
    public static String encrypt(String content, String encryptKey) throws Exception {
        KeyGenerator kgen = KeyGenerator.getInstance("AES");
        kgen.init(128);
        Cipher cipher = Cipher.getInstance(ALGORITHMSTR);
        cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(encryptKey.getBytes(), "AES"));
        byte[] b = cipher.doFinal(content.getBytes("utf-8"));
        // 采用base64算法进行转码,避免出现中文乱码
        return Base64.encodeBase64String(b);
     * @param encryptStr 解密的字符串
     * @param decryptKey 解密的key值
     * @return
     * @throws Exception
    public static String decrypt(String encryptStr, String decryptKey) throws Exception {
        KeyGenerator kgen = KeyGenerator.getInstance("AES");
        kgen.init(128);
        Cipher cipher = Cipher.getInstance(ALGORITHMSTR);
        cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(decryptKey.getBytes(), "AES"));
        // 采用base64算法进行转码,避免出现中文乱码
        byte[] encryptBytes = Base64.decodeBase64(encryptStr);
        byte[] decryptBytes = cipher.doFinal(encryptBytes);
        return new String(decryptBytes);
    public static String encrypt(String content) throws Exception {
        return encrypt(content, KEY);
    public static String decrypt(String encryptStr) throws Exception {
        return decrypt(encryptStr, KEY);
    public static void main(String[] args) throws Exception {
        Map map=new HashMap<String,String>();
        map.put("key","value");
        map.put("中文","汉字");
        String content = JSONObject.toJSONString(map);
        System.out.println("加密前:" + content);
        String encrypt = encrypt(content, KEY);
        System.out.println("加密后:" + encrypt);
        String decrypt = decrypt(encrypt, KEY);
        System.out.println("解密后:" + decrypt);
import org.springframework.web.bind.annotation.Mapping;
import java.lang.annotation.*;
 * @author monkey
 * @desc 请求数据解密
 * @date 2018/10/25 20:17
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Mapping
@Documented
public @interface SecurityParameter {
     * 入参是否解密,默认解密
    boolean inDecode() default true;
     * 出参是否加密,默认加密
    boolean outEncode() default true;

DecodeRequestAdvice类

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Type;
 * @author monkey
 * @desc 请求数据解密
 * @date 2018/10/25 20:17
@ControllerAdvice(basePackages = "com.xxx.springboot.demo.controller")
public class DecodeRequestBodyAdvice implements RequestBodyAdvice {
    private static final Logger logger = LoggerFactory.getLogger(DecodeRequestBodyAdvice.class);
    @Override
    public boolean supports(MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
        return true;
    @Override
    public Object handleEmptyBody(Object body, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
        return body;
    @Override
    public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) throws IOException {
        try {
            boolean encode = false;
            if (methodParameter.getMethod().isAnnotationPresent(SecurityParameter.class)) {
                //获取注解配置的包含和去除字段
                SecurityParameter serializedField = methodParameter.getMethodAnnotation(SecurityParameter.class);
                //入参是否需要解密
                encode = serializedField.inDecode();
            if (encode) {
                logger.info("对方法method :【" + methodParameter.getMethod().getName() + "】返回数据进行解密");
                return new MyHttpInputMessage(inputMessage);
            }else{
                return inputMessage;
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("对方法method :【" + methodParameter.getMethod().getName() + "】返回数据进行解密出现异常:"+e.getMessage());
            return inputMessage;
    @Override
    public Object afterBodyRead(Object body, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
        return body;
    class MyHttpInputMessage implements HttpInputMessage {
        private HttpHeaders headers;
        private InputStream body;
        public MyHttpInputMessage(HttpInputMessage inputMessage) throws Exception {
            this.headers = inputMessage.getHeaders();
            this.body = IOUtils.toInputStream(AesEncryptUtils.decrypt(easpString(IOUtils.toString(inputMessage.getBody(), "UTF-8"))), "UTF-8");
        @Override
        public InputStream getBody() throws IOException {
            return body;
        @Override
        public HttpHeaders getHeaders() {
            return headers;
         * @param requestData
         * @return
        public String easpString(String requestData){
            if(requestData != null && !requestData.equals("")){
                String s = "{\"requestData\":";
                if(!requestData.startsWith(s)){
                    throw new RuntimeException("参数【requestData】缺失异常!");
                }else{
                    int closeLen = requestData.length()-1;
                    int openLen = "{\"requestData\":".length();
                    String substring = StringUtils.substring(requestData, openLen, closeLen);
                    return substring;
            return "";

EncodeResponseAdvice类:

import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
 * @author monkey
 * @desc 返回数据加密
 * @date 2018/10/25 20:17
@ControllerAdvice(basePackages = "com.xxx.springboot.demo.controller")
public class EncodeResponseBodyAdvice implements ResponseBodyAdvice {
    private final static Logger logger = LoggerFactory.getLogger(EncodeResponseBodyAdvice.class);
    @Override
    public boolean supports(MethodParameter methodParameter, Class aClass) {
        return true;
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        boolean encode = false;
        if (methodParameter.getMethod().isAnnotationPresent(SecurityParameter.class)) {
            //获取注解配置的包含和去除字段
            SecurityParameter serializedField = methodParameter.getMethodAnnotation(SecurityParameter.class);
            //出参是否需要加密
            encode = serializedField.outEncode();
        if (encode) {
            logger.info("对方法method :【" + methodParameter.getMethod().getName() + "】返回数据进行加密");
            ObjectMapper objectMapper = new ObjectMapper();
            try {
                String result = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(body);
                return AesEncryptUtils.encrypt(result);
            } catch (Exception e) {
                e.printStackTrace();
                logger.error("对方法method :【" + methodParameter.getMethod().getName() + "】返回数据进行解密出现异常:"+e.getMessage());
        return body;
@Controller
public class TestController {
     * 测试返回数据,会自动加密
     * @return
    @GetMapping("/get")
    @ResponseBody
    @SecurityParameter
    public Object get() {
        Persion info = new Persion();
        info.setName("好看");
        return info;
     * 自动解密,并将返回信息加密
     * @param info
     * @return
    @RequestMapping("/save")
    @ResponseBody
    @SecurityParameter
    public Object save(@RequestBody Persion info) {
        System.out.println(info.getName());
        return info;

引入js文件:地址https://download.csdn.net/download/baidu_38990811/10744745

由于spring boot默认不支持jsp,所以我为了方便直接采用了thymeleaf模板引擎,用法其实很简单,有兴趣的可以去学学

静态页面的return默认是跳转到/static/index.html,当在pom.xml中引入了thymeleaf组件,动态跳转会覆盖默认的静态跳转,默认就会跳转到/templates/index.html,所以只需要访问http://localhost:8080就可以了,动态没有html后缀。

整个流程,我已经测试过了,完全没问题,只不过,采用对称加密,秘钥相同,前后端都需要拿到秘钥才能进行加解密,这样就有秘钥泄露的风险了,服务端还好说一点,安全稍微高点,但是前端就比较有风险,所以前端要考虑,js进行混淆和加密,当然只能让风险降低,也不是完全没风险了!!!

后续可以考虑: 对称加密和非对称加密联合使用来进行加密,各取长处,但是代码要复杂些!

参考文章:
1. https://github.com/yinjihuan/spring-boot-starter-encrypt (仔细看)
2.https://blog.csdn.net/qq_32079585/article/details/77867097 (可以快速看)
3.https://blog.csdn.net/junmoxi/article/details/80917234?utm_source=blogxgwz2 (复杂的方式,不过扩展的好)
4.https://blog.csdn.net/huang812561/article/details/79424041?utm_source=blogxgwz1(参考)

前言:1.最近要做一个安全性稍微高一点的项目,首先就想到了要对参数加密,和采用https协议.2.以前对加密这块不了解,查阅了很多资料,加密方式很多种,但是大概区分两种,一个就是对称加密(DES,3DES,AES,IDEA等),另外一个就是非对称加密(RSA,Elgamal,背包算法,Rabin,D-H等)3.这两种区别还是有的,粗浅的说:(1)对称加密方式效率高,但是有泄露风险... spring boot数据传输加密工具jar包开源代码,可自行调整 使用步骤 打包进入工程根目录下执行maven命令:mvn clean package -Dmaven.test.skip = true 通过启动example工程:SpringBootStarterEncryptExampleApplication 浏览器访问页面: 获取数据按钮:无前端入参,重新返回加密数据发送数据按钮:前端json提交加密参数,扩展解析并返回加密出参
文章目录若依框架登录功能进行AES加密1. 引入crypto-js2. 项目引入JS前端加密 若依框架登录功能进行AES加密 前言: 项目在渗透测试时发现若依平台登录接口未加密,所以需要对登录信息进行加密处理下面就直接开始 1. 引入crypto-js 百度网盘链接:https://pan.baidu.com/s/1omNoh4GbuyDp3JG3wXQ5sw 提取码:3udt 2. 项目引入JS前端加密 将下载的JS放入项目中(此处我方在resource–>rouyi)下的 ## 调整前端登
1.最近要做一个安全性稍微高一点的项目,首先就想到了要对参数加密,和采用https协议. 2.以前对加密这块不了解,查阅了很多资料,加密方式很多种,但是大概区分两种,一个就是对称加密(DES,3DES,AES,IDEA等),另外一个就是非对称加密(RSA,Elgamal,背包算法,Rabin,D-H等) 3.这两种区别还是有的,粗浅的说: (1)对称加密方式效率高,但是有泄露风险 (2)非对... CSDN-Ada助手: 嗨~好久未见你更新博文了,我们现在上线了AI创作助手哦~可为你的创作提供智能化帮助,快来试试吧~https://editor.csdn.net/md/?not_checkout=1&utm_source=blog_comment_recall,在编辑器页面右侧哦~~限免!! 同时我们为您准备了一份回归奖励,快来看看吧https://activity.csdn.net/creatActivity?id=10430&utm_source=blog_comment_recall MYSQL 查询所有上级and查询所有下级的sql AlexLv戳戳: 请问放到代码中怎么用呢,会报错 谷歌(Google): reCaptcha(2.0版本)做网站验证码 coderjiangyu: 我也是,你怎么处理的 学习加密(三)spring boot 使用RSA非对称加密,前后端传递参数加解密 三十岁之前尽量不秃: 学习加密(三)spring boot 使用RSA非对称加密,前后端传递参数加解密 三十岁之前尽量不秃: