龙空技术网

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

溪云阁 4954

前言:

今天朋友们对“java加密算法包”大致比较珍视,同学们都想要剖析一些“java加密算法包”的相关内容。那么小编同时在网上网罗了一些对于“java加密算法包””的相关资讯,希望姐妹们能喜欢,各位老铁们快快来了解一下吧!

溪云阁:专注编程教学,架构,JAVA,Python,微服务,机器学习等,欢迎关注

上一篇:springboot2.2.X手册:redis的7种类型100个方法全解析

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

接口安全防什么

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)@Documentedpublic @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日 */@ControllerAdvicepublic 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);    }}
测试

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

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

--END--

作者:@溪云阁

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

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

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

标签: #java加密算法包 #java防抓包代码