您当前的位置:首页 > 电脑百科 > 程序开发 > 架构

springboot2.2.X手册:防抓包?快速实现API接口数据加密

时间:2020-06-20 16:04:39  来源:  作者:

有没有遇到这样子的接口,放到互联网上面去,谁都可以调用,谁都可以访问,完全就是公开的,这样子的接口,如果只是普通的数据,其实可以考虑,只是可以考虑,但是,一般情况下,我们是不允许这样子做的。

springboot2.2.X手册:防抓包?快速实现API接口数据加密

 

接口安全防什么

1、防止恶意调用攻击

2、防止篡改信息攻击

3、防拦截攻击,数据被截取后进行修改后重新放回去

4、防止数据泄漏攻击

 

什么是抓包

抓包(packet capture)就是将网络传输发送与接收的数据包进行截获、重发、编辑、转存等操作,也用来检查网络安全。抓包也经常被用来进行数据截取等。

这是百度百科给我们的解释,当我们一些放到互联网上的数据,直接采用明文的话,就很容易被抓包,然后进行修改或者被恶意植入木马,这是比较恶心的行为,今天我们就来研究一下怎么样对接口进行数据加密。

 

POM文件

 <!-- springboot核心web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- 配置包,用于配置属性文件 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
        </dependency>

        <!-- 统一API包 -->
        <dependency>
			<groupId>com.boots</groupId>
			<artifactId>module-boots-api</artifactId>
			<version>2.0.0.RELEASE</version>
		</dependency>

编写加密解密工具类

/**
 * All rights Reserved, Designed By 林溪
 * Copyright:    Copyright(C) 2016-2020
 * Company       溪云阁 .
 */

package com.module.boots.api.de.utils;

import JAVA.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import org.Apache.Tomcat.util.codec.binary.Base64;

import com.module.boots.exception.CommonRuntimeException;

/**
 * AES加密解密
 * @author:溪云阁
 * @date:2020年6月4日
 */
public class AesUtils {

    private static final String KEY_ALGORITHM = "AES";

    private static final String DEFAULT_CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding";// 默认的加密算法

    /**
     * AES 加密操作
     * @author 溪云阁
     * @param content 待加密内容
     * @param password 加密密码
     * @return String 返回Base64转码后的加密数据
     */
    public static String encrypt(String content, String password) {
        try {
            // 创建密码器
            final Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);
            // 设置为UTF-8编码
            final byte[] byteContent = content.getBytes("utf-8");
            // 初始化为加密模式的密码器
            cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(password));
            // 加密
            final byte[] result = cipher.doFinal(byteContent);
            // 通过Base64转码返回
            return Base64.encodeBase64String(result);

        }
        catch (final Exception ex) {
            throw new CommonRuntimeException(ex.fillInStackTrace());

        }
    }

    /**
     * AES 解密操作
     * @author 溪云阁
     * @param content
     * @param password
     * @return String
     */
    public static String decrypt(String content, String password) {
        try {
            // 实例化
            final Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);
            // 使用密钥初始化,设置为解密模式
            cipher.init(Cipher.DECRYPT_MODE, getSecretKey(password));
            // 执行操作
            final byte[] result = cipher.doFinal(Base64.decodeBase64(content));
            // 采用UTF-8编码转化为字符串
            return new String(result, "utf-8");

        }
        catch (final Exception ex) {
            throw new CommonRuntimeException(ex.fillInStackTrace());
        }

    }

    /**
     * 生成加密秘钥
     * @author 溪云阁
     * @param password 加密的密码
     * @return SecretKeySpec
     */
    private static SecretKeySpec getSecretKey(final String password) {
        // 返回生成指定算法密钥生成器的 KeyGenerator 对象
        KeyGenerator kg = null;
        try {
            kg = KeyGenerator.getInstance(KEY_ALGORITHM);
            // AES 要求密钥长度为 128
            kg.init(128, new SecureRandom(password.getBytes()));
            // 生成一个密钥
            final SecretKey secretKey = kg.generateKey();
            // 转换为AES专用密钥
            return new SecretKeySpec(secretKey.getEncoded(), KEY_ALGORITHM);
        }
        catch (final NoSuchAlgorithmException ex) {
            throw new CommonRuntimeException(ex.fillInStackTrace());
        }
    }

    public static void main(String[] args) {
        final String str = "V9JofCHn02eyXRiDb1VuseRSuOgEQftROwudMPWwMAO2Wk5K7aYZ4Vtm6xiTn5i5";
        System.out.println(decrypt(str, "xy934yrn9342u0ry4br8cn-9u2"));
    }

}

编写加密注解

/**
 * All rights Reserved, Designed By 林溪
 * Copyright:    Copyright(C) 2016-2020
 * Company       溪云阁 .
 */

package com.module.boots.api.de;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 返回对body加密,针对类跟方法
 * @author:溪云阁
 * @date:2020年6月4日
 */
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ResponseEncrypt {

    /**
     * 返回对body加密,默认是true
     * @author 溪云阁
     * @return boolean
     */
    boolean value() default true;
}

编写加密判断类

/**
 * All rights Reserved, Designed By 林溪
 * Copyright:    Copyright(C) 2016-2020
 * Company       溪云阁 .
 */

package com.module.boots.api.de;

import org.springframework.core.MethodParameter;

/**
 * 是否需要加密解密
 * @author:溪云阁
 * @date:2020年6月4日
 */
public class NeedDe {

    /**
     * 判断是否需要加密
     * @author 溪云阁
     * @param returnType
     * @return boolean
     */
    public static boolean needEncrypt(MethodParameter returnType) {
        boolean encrypt = false;
        // 获取类上的注解
        final boolean classPresentAnno = returnType.getContainingClass().isAnnotationPresent(ResponseEncrypt.class);
        // 获取方法上的注解
        final boolean methodPresentAnno = returnType.getMethod().isAnnotationPresent(ResponseEncrypt.class);
        if (classPresentAnno) {
            // 类上标注的是否需要加密
            encrypt = returnType.getContainingClass().getAnnotation(ResponseEncrypt.class).value();
            // 类不加密,所有都不加密
            if (!encrypt) {
                return false;
            }
        }
        if (methodPresentAnno) {
            // 方法上标注的是否需要加密
            encrypt = returnType.getMethod().getAnnotation(ResponseEncrypt.class).value();
        }
        return encrypt;
    }

}

编写加密拦截

/**
 * All rights Reserved, Designed By 林溪
 * Copyright:    Copyright(C) 2016-2020
 * Company       溪云阁 .
 */

package com.module.boots.api.de;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
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;

import com.module.boots.api.de.utils.AesUtils;
import com.module.boots.api.message.ResponseMsg;

/**
 * 对接口数据进行加密
 * @author:溪云阁
 * @date:2020年6月4日
 */
@ControllerAdvice
public class ResponseEncryptAdvice implements ResponseBodyAdvice<Object> {

    @Value("${module.boots.response.aes.key}")
    private String key;

    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        return true;
    }

    /**
     * 在写入之前更改body的值
     * @author 溪云阁
     * @param body
     * @param returnType
     * @param selectedContentType
     * @param selectedConverterType
     * @param request
     * @param response
     * @return
     * @return
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
            Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request,
            ServerHttpResponse response) {
        // 判断是否需要加密
        final boolean encrypt = NeedDe.needEncrypt(returnType);
        if (!encrypt) {
            return body;
        } else {
            // 如果body是属于ResponseMsg类型,只需要对data里面的数据进行加密即可
            if (body instanceof ResponseMsg) {
                final ResponseMsg responseMsg = (ResponseMsg) body;
                final Object data = responseMsg.getData();
                if (data == null) {
                    return body;
                } else {
                    responseMsg.setData(AesUtils.encrypt(data.toString(), key));
                    return responseMsg;
                }
            } else {
                return body;
            }
        }
    }

}

加入密钥

# aes的密钥
module.boots.response.aes.key: xy934yrn9342u0ry4br8cn-9u2

编写加密解密接口

/**
 * All rights Reserved, Designed By 林溪
 * Copyright:    Copyright(C) 2016-2020
 * Company       溪云阁 .
 */

package com.boots.api.de.view.de.view;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMApping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.boots.api.de.view.de.vo.GetEncryptVO;
import com.module.boots.api.de.ResponseEncrypt;
import com.module.boots.api.de.utils.AesUtils;
import com.module.boots.api.message.ResponseMsg;
import com.module.boots.api.utils.MsgUtils;
import com.module.boots.exception.CommonRuntimeException;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.SneakyThrows;

/**
 * 加密数据接口
 * @author:溪云阁
 * @date:2020年6月4日
 */
@SuppressWarnings("deprecation")
@Api(tags = { "web服务:加密数据接口" })
@RestController
@RequestMapping("view/deView")
public class DeView {

    @Value("${module.boots.response.aes.key}")
    private String key;

    /**
     * 获取加密数据
     * @author 溪云阁
     * @return ResponseMsg<GetDeVO>
     */
    @ApiOperation(value = "获取加密数据")
    @GetMapping(value = "/getEncrypt", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    @SneakyThrows(CommonRuntimeException.class)
    @ResponseEncrypt
    public ResponseMsg<GetEncryptVO> getEncrypt() {
        final GetEncryptVO vo = new GetEncryptVO();
        vo.setId("b037123c");
        vo.setUserName("xnwqr98urx");
        return MsgUtils.buildSuccessMsg(vo);
    }

    /**
     * 获取解密数据
     * @author 溪云阁
     * @return ResponseMsg<GetDeVO>
     */
    @ApiOperation(value = "获取解密数据")
    @GetMapping(value = "/getDecrypt", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    @SneakyThrows(CommonRuntimeException.class)
    public ResponseMsg<String> getDecrypt(@RequestParam(value = "content") String content) {
        final String str = AesUtils.decrypt(content, key);
        return MsgUtils.buildSuccessMsg(str);
    }

}

测试

springboot2.2.X手册:防抓包?快速实现API接口数据加密

 


springboot2.2.X手册:防抓包?快速实现API接口数据加密

 

从实验的结果上看,我们在获取数据的时候,直接对data里面的数据进行了加密,这种加密方式只有我们自己可以破解,放到网上去,即使只有密钥,也破解不了。

这里只做接口的数据的加密,生产中经常需要加入token,时间戳等进行验证,各位同学自行拓展即可。

--END--

作者:@溪云阁

原创作品,抄袭必究,转载注明出处

如需要源码,转发,关注后私信我

部分图片或代码来源网络,如侵权请联系删除,谢谢!



Tags:springboot   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
我是一名程序员关注我们吧,我们会多多分享技术和资源。进来的朋友,可以多了解下青锋的产品,已开源多个产品的架构版本。Thymeleaf版(开源)1、采用技术: springboot、layui、Thymel...【详细内容】
2021-12-14  Tags: springboot  点击:(21)  评论:(0)  加入收藏
前言项目中的配置文件会有密码的存在,例如数据库的密码、邮箱的密码、FTP的密码等。配置的密码以明文的方式暴露,并不是一种安全的方式,特别是大型项目的生产环境中,因为配置文...【详细内容】
2021-11-17  Tags: springboot  点击:(25)  评论:(0)  加入收藏
SpringBoot开发的物联网通信平台系统项目功能模块 功能 说明 MQTT 1.SSL支持 2.集群化部署时暂不支持retain&will类型消 UDP ...【详细内容】
2021-11-05  Tags: springboot  点击:(56)  评论:(0)  加入收藏
1. 介绍1.1 介绍今天开始我们来学习Java操作MySQL数据库的技巧,Java操作MySQL是借助JdbcTemplate这个对象来实现的。JdbcTemplate是一个多数据库集中解决方案,而我们今天只讲...【详细内容】
2021-11-05  Tags: springboot  点击:(30)  评论:(0)  加入收藏
SpringBoot中的Controller注册本篇将会以Servlet为切入点,通过源码来看web容器中的Controller是如何注册到HandlerMapping中。请求来了之后,web容器是如何根据请求路径找到对...【详细内容】
2021-11-04  Tags: springboot  点击:(53)  评论:(0)  加入收藏
环境:Springboot2.4.11环境配置接下来的演示都是基于如下接口进行。@RestController@RequestMapping("/exceptions")public class ExceptionsController { @GetMapping(...【详细内容】
2021-10-11  Tags: springboot  点击:(41)  评论:(0)  加入收藏
SpringBoot项目默认使用logback, 已经内置了 logback 的相关jar包,会从resource包下查找logback.xml, logback 文件格式范本 可直接复制使用,有控制台 info.log error.log三个...【详细内容】
2021-10-09  Tags: springboot  点击:(50)  评论:(0)  加入收藏
环境:Springboot2.4.10当应用程序启动时,Spring Boot将自动从以下位置查找并加载application.properties和application.yaml文件: 从Classpath类路径classpath的根类路径classp...【详细内容】
2021-09-26  Tags: springboot  点击:(78)  评论:(0)  加入收藏
搭建基础1. Intellij IDEA 2. jdk1.8 3. maven3.6.3搭建方式(1)在线创建项目Spring Boot 官方提供的一种创建方式,在浏览器中访问如下网址: https://start.spring.io/在打开的页...【详细内容】
2021-09-14  Tags: springboot  点击:(78)  评论:(0)  加入收藏
最近开发项目的时候需要用到对象的属性拷贝,以前也有用过一些复制框架,比如spring的 BeanUtils.copyProperties等方式,但总是不尽如人意,最近发现使用orika进行对象拷贝挺好用的...【详细内容】
2021-08-27  Tags: springboot  点击:(231)  评论:(0)  加入收藏
▌简易百科推荐
为了构建高并发、高可用的系统架构,压测、容量预估必不可少,在发现系统瓶颈后,需要有针对性地扩容、优化。结合楼主的经验和知识,本文做一个简单的总结,欢迎探讨。1、QPS保障目标...【详细内容】
2021-12-27  大数据架构师    Tags:架构   点击:(5)  评论:(0)  加入收藏
前言 单片机开发中,我们往往首先接触裸机系统,然后到RTOS,那么它们的软件架构是什么?这是我们开发人员必须认真考虑的问题。在实际项目中,首先选择软件架构是非常重要的,接下来我...【详细内容】
2021-12-23  正点原子原子哥    Tags:架构   点击:(7)  评论:(0)  加入收藏
现有数据架构难以支撑现代化应用的实现。 随着云计算产业的快速崛起,带动着各行各业开始自己的基于云的业务创新和信息架构现代化,云计算的可靠性、灵活性、按需计费的高性价...【详细内容】
2021-12-22    CSDN  Tags:数据架构   点击:(10)  评论:(0)  加入收藏
▶ 企业级项目结构封装释义 如果你刚毕业,作为Java新手程序员进入一家企业,拿到代码之后,你有什么感觉呢?如果你没有听过多模块、分布式这类的概念,那么多半会傻眼。为什么一个项...【详细内容】
2021-12-20  蜗牛学苑    Tags:微服务   点击:(9)  评论:(0)  加入收藏
我是一名程序员关注我们吧,我们会多多分享技术和资源。进来的朋友,可以多了解下青锋的产品,已开源多个产品的架构版本。Thymeleaf版(开源)1、采用技术: springboot、layui、Thymel...【详细内容】
2021-12-14  青锋爱编程    Tags:后台架构   点击:(21)  评论:(0)  加入收藏
在了解连接池之前,我们需要对长、短链接建立初步认识。我们都知道,网络通信大部分都是基于TCP/IP协议,数据传输之前,双方通过“三次握手”建立连接,当数据传输完成之后,又通过“四次挥手”释放连接,以下是“三次握手”与“四...【详细内容】
2021-12-14  架构即人生    Tags:连接池   点击:(17)  评论:(0)  加入收藏
随着移动互联网技术的快速发展,在新业务、新领域、新场景的驱动下,基于传统大型机的服务部署方式,不仅难以适应快速增长的业务需求,而且持续耗费高昂的成本,从而使得各大生产厂商...【详细内容】
2021-12-08  架构驿站    Tags:分布式系统   点击:(23)  评论:(0)  加入收藏
本系列为 Netty 学习笔记,本篇介绍总结Java NIO 网络编程。Netty 作为一个异步的、事件驱动的网络应用程序框架,也是基于NIO的客户、服务器端的编程框架。其对 Java NIO 底层...【详细内容】
2021-12-07  大数据架构师    Tags:Netty   点击:(16)  评论:(0)  加入收藏
前面谈过很多关于数字化转型,云原生,微服务方面的文章。虽然自己一直做大集团的SOA集成平台咨询规划和建设项目,但是当前传统企业数字化转型,国产化和自主可控,云原生,微服务是不...【详细内容】
2021-12-06  人月聊IT    Tags:架构   点击:(23)  评论:(0)  加入收藏
微服务看似是完美的解决方案。从理论上来说,微服务提高了开发速度,而且还可以单独扩展应用的某个部分。但实际上,微服务带有一定的隐形成本。我认为,没有亲自动手构建微服务的经历,就无法真正了解其复杂性。...【详细内容】
2021-11-26  GreekDataGuy  CSDN  Tags:单体应用   点击:(35)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条