亚洲视频二区_亚洲欧洲日本天天堂在线观看_日韩一区二区在线观看_中文字幕不卡一区

公告:魔扣目錄網(wǎng)為廣大站長提供免費收錄網(wǎng)站服務(wù),提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.430618.com 】, 免友鏈快審服務(wù)(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

有沒有遇到這樣子的接口,放到互聯(lián)網(wǎng)上面去,誰都可以調(diào)用,誰都可以訪問,完全就是公開的,這樣子的接口,如果只是普通的數(shù)據(jù),其實可以考慮,只是可以考慮,但是,一般情況下,我們是不允許這樣子做的。

springboot2.2.X手冊:防抓包?快速實現(xiàn)API接口數(shù)據(jù)加密

 

接口安全防什么

1、防止惡意調(diào)用攻擊

2、防止篡改信息攻擊

3、防攔截攻擊,數(shù)據(jù)被截取后進(jìn)行修改后重新放回去

4、防止數(shù)據(jù)泄漏攻擊

 

什么是抓包

抓包(packet capture)就是將網(wǎng)絡(luò)傳輸發(fā)送與接收的數(shù)據(jù)包進(jìn)行截獲、重發(fā)、編輯、轉(zhuǎn)存等操作,也用來檢查網(wǎng)絡(luò)安全。抓包也經(jīng)常被用來進(jìn)行數(shù)據(jù)截取等。

這是百度百科給我們的解釋,當(dāng)我們一些放到互聯(lián)網(wǎng)上的數(shù)據(jù),直接采用明文的話,就很容易被抓包,然后進(jìn)行修改或者被惡意植入木馬,這是比較惡心的行為,今天我們就來研究一下怎么樣對接口進(jìn)行數(shù)據(jù)加密。

 

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>

        <!-- 統(tǒng)一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";// 默認(rèn)的加密算法

    /**
     * AES 加密操作
     * @author 溪云閣
     * @param content 待加密內(nèi)容
     * @param password 加密密碼
     * @return String 返回Base64轉(zhuǎn)碼后的加密數(shù)據(jù)
     */
    public static String encrypt(String content, String password) {
        try {
            // 創(chuàng)建密碼器
            final Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);
            // 設(shè)置為UTF-8編碼
            final byte[] byteContent = content.getBytes("utf-8");
            // 初始化為加密模式的密碼器
            cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(password));
            // 加密
            final byte[] result = cipher.doFinal(byteContent);
            // 通過Base64轉(zhuǎn)碼返回
            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);
            // 使用密鑰初始化,設(shè)置為解密模式
            cipher.init(Cipher.DECRYPT_MODE, getSecretKey(password));
            // 執(zhí)行操作
            final byte[] result = cipher.doFinal(Base64.decodeBase64(content));
            // 采用UTF-8編碼轉(zhuǎn)化為字符串
            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();
            // 轉(zhuǎn)換為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加密,默認(rèn)是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) {
            // 類上標(biāo)注的是否需要加密
            encrypt = returnType.getContainingClass().getAnnotation(ResponseEncrypt.class).value();
            // 類不加密,所有都不加密
            if (!encrypt) {
                return false;
            }
        }
        if (methodPresentAnno) {
            // 方法上標(biāo)注的是否需要加密
            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;

/**
 * 對接口數(shù)據(jù)進(jìn)行加密
 * @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里面的數(shù)據(jù)進(jìn)行加密即可
            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;

/**
 * 加密數(shù)據(jù)接口
 * @author:溪云閣
 * @date:2020年6月4日
 */
@SuppressWarnings("deprecation")
@Api(tags = { "web服務(wù):加密數(shù)據(jù)接口" })
@RestController
@RequestMapping("view/deView")
public class DeView {

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

    /**
     * 獲取加密數(shù)據(jù)
     * @author 溪云閣
     * @return ResponseMsg<GetDeVO>
     */
    @ApiOperation(value = "獲取加密數(shù)據(jù)")
    @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);
    }

    /**
     * 獲取解密數(shù)據(jù)
     * @author 溪云閣
     * @return ResponseMsg<GetDeVO>
     */
    @ApiOperation(value = "獲取解密數(shù)據(jù)")
    @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手冊:防抓包?快速實現(xiàn)API接口數(shù)據(jù)加密

 


springboot2.2.X手冊:防抓包?快速實現(xiàn)API接口數(shù)據(jù)加密

 

從實驗的結(jié)果上看,我們在獲取數(shù)據(jù)的時候,直接對data里面的數(shù)據(jù)進(jìn)行了加密,這種加密方式只有我們自己可以破解,放到網(wǎng)上去,即使只有密鑰,也破解不了。

這里只做接口的數(shù)據(jù)的加密,生產(chǎn)中經(jīng)常需要加入token,時間戳等進(jìn)行驗證,各位同學(xué)自行拓展即可。

--END--

作者:@溪云閣

原創(chuàng)作品,抄襲必究,轉(zhuǎn)載注明出處

如需要源碼,轉(zhuǎn)發(fā),關(guān)注后私信我

部分圖片或代碼來源網(wǎng)絡(luò),如侵權(quán)請聯(lián)系刪除,謝謝!

分享到:
標(biāo)簽:springboot
用戶無頭像

網(wǎng)友整理

注冊時間:

網(wǎng)站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨大挑戰(zhàn)2018-06-03

數(shù)獨一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運動步數(shù)有氧達(dá)人2018-06-03

記錄運動步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績評定2018-06-03

通用課目體育訓(xùn)練成績評定