溪云閣:專注編程教學,架構,JAVA,Python,微服務,機器學習等,歡迎關注
上一篇:springboot2.2.X手冊:redis的7種類型100個方法全解析
有沒有遇到這樣子的接口,放到互聯網上面去,誰都可以調用,誰都可以訪問,完全就是公開的,這樣子的接口,如果只是普通的數據,其實可以考慮,只是可以考慮,但是,一般情況下,我們是不允許這樣子做的。

接口安全防什么
1、防止惡意調用攻擊
2、防止篡改信息攻擊
3、防攔截攻擊,數據被截取后進行修改后重新放回去
4、防止數據泄漏攻擊

什么是抓包
抓包(packet capture)就是將網絡傳輸發送與接收的數據包進行截獲、重發、編輯、轉存等操作,也用來檢查網絡安全。抓包也經常被用來進行數據截取等。
這是百度百科給我們的解釋,當我們一些放到互聯網上的數據,直接采用明文的話,就很容易被抓包,然后進行修改或者被惡意植入木馬,這是比較惡心的行為,今天我們就來研究一下怎么樣對接口進行數據加密。

POM文件
org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-autoconfigure com.bootsmodule-boots-api2.0.0.RELEASE
編寫加密解密工具類
/** * 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 { @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 */ @ApiOperation(value = "獲取加密數據") @GetMapping(value = "/getEncrypt", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) @SneakyThrows(CommonRuntimeException.class) @ResponseEncrypt public ResponseMsg getEncrypt() { final GetEncryptVO vo = new GetEncryptVO(); vo.setId("b037123c"); vo.setUserName("xnwqr98urx"); return MsgUtils.buildSuccessMsg(vo); } /** * 獲取解密數據 * @author 溪云閣 * @return ResponseMsg */ @ApiOperation(value = "獲取解密數據") @GetMapping(value = "/getDecrypt", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) @SneakyThrows(CommonRuntimeException.class) public ResponseMsg getDecrypt(@RequestParam(value = "content") String content) { final String str = AesUtils.decrypt(content, key); return MsgUtils.buildSuccessMsg(str); }}
測試


從實驗的結果上看,我們在獲取數據的時候,直接對data里面的數據進行了加密,這種加密方式只有我們自己可以破解,放到網上去,即使只有密鑰,也破解不了。
這里只做接口的數據的加密,生產中經常需要加入token,時間戳等進行驗證,各位同學自行拓展即可。
--END--
作者:@溪云閣
原創作品,抄襲必究,轉載注明出處
如需要源碼,轉發,關注后私信我
部分圖片或代碼來源網絡,如侵權請聯系刪除,謝謝!