最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JAVA實現(xiàn)sm3加密簽名以及防止重復攻擊

 更新時間:2023年10月31日 15:59:41   作者:小白的碼BUG之路  
這篇文章主要給大家介紹了關于JAVA實現(xiàn)sm3加密簽名以及防止重復攻擊的相關資料,SM3是簽名算法,和MD5一樣(對于應用層來說),SM4是對稱加密算法,和AES一樣(對于應用層來說),需要的朋友可以參考下

背景:

后端開發(fā)基本都遇到過使用簽名校驗的情況,簽名的作用是為了防止請求數(shù)據(jù)被別人截取篡改重新請求。

為什么簽名驗證可以防止請求數(shù)據(jù)被篡改,因為一般簽名的規(guī)則就是,你的所有請求參數(shù),按照約定好的格式進行拼接,后面得到一個拼接后的字符串,這個字符串后面再加上一個雙方私下確認后的簽名秘鑰(固定),最后組合成一個待簽名字符串,用這個字符串進行sm3加密。sm3加密是個不可逆的加密(理論上),請求方把這個加密后面簽名字段放到請求頭中,服務提供方本地根據(jù)相同的方法進行組合簽名字符串和加密,然后對面本地加密的簽名和請求頭中的簽名是否相同,相同則認為這個數(shù)據(jù)是可靠的,未被篡改過的(加密前數(shù)據(jù)不同,加密后的簽名肯定不同)。

PS:簽名只能驗證防止請求數(shù)據(jù)被篡改,并不能說你把數(shù)據(jù)加密讓別人看不見,只要是互聯(lián)網上傳輸,數(shù)據(jù)就可能被別人獲取到

簽名優(yōu)化:

請求頭加上時間戳,代碼上驗證請求的時間戳和當前時間戳時間差距,差距過大就拒絕請求(比如只接受一分鐘內請求),同時把這個時間戳加到簽名字符串去,這樣簽名的數(shù)據(jù)內容就包含時間戳(可以防止別人用同一份簽名發(fā)起重復請求攻擊,因為時間戳是一直在變的,簽名中的時間戳和請求報文頭的時間戳不同,驗證簽名就不會通過),這樣就可以做到即使有人獲取到了某個請求的參數(shù)和簽名,以此發(fā)起多次重復請求攻擊,這種攻擊最多只有一分鐘的有效期。

代碼:

package com.dw.task.utils;

import cn.hutool.crypto.SmUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.lang.reflect.Field;
import java.util.Objects;

@Slf4j
@Component
public class Sm3UtilHua {

    private static Integer httpCheckSignTimeOut = 1;//請求簽名有效時間 默認1分鐘

    /**
     * 獲取實體類拼成的加密字段
     * @param checkSign  前端傳入的簽名(從請求報文頭獲?。?
     * @param signModel  查詢的DTO模型類
     * @param privateKey  簽名加密私鑰
     * @param timestamp  時間戳(從請求報文頭獲取)
     * @return  比對結果
     */
    public boolean checkSign(String checkSign , Object signModel , String privateKey,Long timestamp) throws Exception {
        Long thisTime = System.currentTimeMillis() - timestamp;
        Integer checkSignTimeOut = httpCheckSignTimeOut;
        if (!(Objects.isNull(checkSignTimeOut) || checkSignTimeOut.intValue() == 0)){
            //時間為0或者未配置簽名超時時間,默認不驗證時間戳
            if(thisTime >= 60*1000*checkSignTimeOut || thisTime<=0){
                //checkSignTimeOut分鐘內的時間戳才處理
                log.error("時間戳異常,非"+checkSignTimeOut+"分鐘內請求,當前時間戳:"+System.currentTimeMillis());
                return false;
            }
        }
        String signValue = getSignValue(signModel) + "&timestamp=" + timestamp +"&privateKey=" +privateKey;
        String sign = getSign(signValue);
        log.info("【本地加密后 sm3 簽名】" + sign);//生產上建議注釋此行,防止泄露
        return sign.toUpperCase().equals(checkSign.toUpperCase())? true : false;
    }
    /**
     * 加密簽名
     * @param signValue  待加密簽名字符串
     * @return  加密后簽名字符串
     */
    public String getSign(String signValue){
        return SmUtil.sm3(signValue);
    }
    
    /**
     * 獲取實體類拼成的加密字段
     * @param classA  傳入?yún)?shù)實體類
     * @return  待加密字符串
     */
    public  String getSignValue(Object classA) {
        Field[] fs = classA.getClass().getDeclaredFields();//獲取所有屬性
        String[][] temp = new String[fs.length][2]; //用二維數(shù)組保存  參數(shù)名和參數(shù)值
        for (int i=0; i<fs.length;  i++) {
            fs[i].setAccessible(true);
            temp[i][0] = fs[i].getName().toLowerCase(); //獲取屬性名
            try {
                temp[i][1] = String.valueOf(fs[i].get(classA)) ;//把屬性值放進數(shù)組
            }  catch (Exception e) {
                log.error("【簽名字段:"+fs[i].getName()+"添加失敗】");
            }
        }
        temp = doChooseSort(temp); //對參數(shù)實體類按照字母順序排續(xù)
        String result = "";
        for (int i = 0; i < temp.length; i++) {//按照簽名規(guī)則生成待加密字符串
            result = result + temp[i][0]+"="+temp[i][1]+"&";
        }
        result = result.substring(0, result.length()-1);//消除掉最后的“&”
        log.info("【簽名信息】{}" ,result);
        return result;
    }

    /**
     * 對二維數(shù)組里面的數(shù)據(jù)進行選擇排序,按字段名按abcd順序排列
     * @param data 未按照字母順序排序的二維數(shù)組
     * @return
     */
    private  String[][] doChooseSort(String[][] data) {//排序方式為選擇排序
        String[][] temp = new String[data.length][2];
        temp = data;
        int n = temp.length;
        for (int i = 0; i < n-1; i++) {
            int k = i;// 初始化最小值的小標
            for (int j = i+1; j<n; j++) {
                if (temp[k][0].compareTo(temp[j][0]) > 0) {    //下標k字段名大于當前字段名
                    k = j;// 修改最大值的小標
                }
            }
            // 將最小值放到排序序列末尾
            if (k > i) {  //用相加相減法交換data[i] 和 data[k]
                String tempValue ;
                tempValue = temp[k][0];
                temp[k][0] = temp[i][0];
                temp[i][0] = tempValue;
                tempValue = temp[k][1];
                temp[k][1] = temp[i][1];
                temp[i][1] = tempValue;
            }
        }
        return temp;
    }

}

測試代碼:

    public static void main(String[] args) throws Exception {
        //模擬請求參數(shù)
        QueryDTO dto = new QueryDTO();
        dto.setName("張三");
        dto.setAge(18);
        dto.setIdCard("666666666666666");
        //模擬請求報文頭時間戳
        Long nowTime = System.currentTimeMillis();
        //簽名加密私鑰(不要在互聯(lián)網上傳輸,調用方和提供方私下物理確認和設置)
        String privateKey = "48d95af20fa1bc438db42e280085707b60841c";

        Sm3UtilHua sm3UtilHua = new Sm3UtilHua();

        System.out.println("1:請求簽名錯誤的案例");
        //模擬請求錯誤的簽名
        String errorSign = "2222222222222222222";
        System.out.println("驗簽校驗結果:" + sm3UtilHua.checkSign(errorSign,dto, privateKey,nowTime));
        System.out.println();

        System.out.println("2:請求簽名正確的案例");
        String signValue = sm3UtilHua.getSignValue(dto) + "&timestamp=" + nowTime +"&privateKey=" +privateKey;//復制上面1請求的加密后簽名
        String trueSign = sm3UtilHua.getSign(signValue);
        System.out.println("驗簽校驗結果:" + sm3UtilHua.checkSign(trueSign,dto, privateKey,nowTime));
        System.out.println();

        System.out.println("3:請求簽名正確,但是時間非一分鐘內請求的案例");
        Long oldTime = 1688036145560L;//這個時間戳大概是2023年06月29號的時間戳,所以必不是當前一分鐘內時間
        System.out.println("驗簽校驗結果:" + sm3UtilHua.checkSign(trueSign,dto, privateKey,oldTime));

    }

測試結果:

下面的簽名信息打印是不完整的,沒有拼接時間戳和簽名私鑰,也是防止打印到日志然后泄露

1:請求簽名錯誤的案例
10:42:11.506 [main] ERROR com.dw.task.utils.Sm3UtilHua - 時間戳異常,非1分鐘內請求,當前時間戳:1688092931498
驗簽校驗結果:false

2:請求簽名正確的案例
10:42:11.522 [main] INFO com.dw.task.utils.Sm3UtilHua - 【簽名信息】age=18&idcard=666666666666666&name=張三
10:42:12.358 [main] INFO com.dw.task.utils.Sm3UtilHua - 【簽名信息】age=18&idcard=666666666666666&name=張三
10:42:12.359 [main] INFO com.dw.task.utils.Sm3UtilHua - 【本地加密后 sm3 簽名】e60bf8ea2453f44a4a6d3b43f55399c2ce09a6f5b4be68378506d95d2d6f4491
驗簽校驗結果:true

3:請求簽名正確,但是時間非一分鐘內請求的案例
10:42:12.359 [main] ERROR com.dw.task.utils.Sm3UtilHua - 時間戳異常,非1分鐘內請求,當前時間戳:1688092932359
驗簽校驗結果:false

引申優(yōu)化:

上面的代碼已經可以防止一定程度的重復請求攻擊,但是一分鐘內的重復請求攻擊還是無法防止的,如果別人截取請求信息后一分鐘內發(fā)起大量重復請求的話,還是會通過簽名并且穿透到業(yè)務層,對此呢如果要再優(yōu)化,就可以把每次驗證成功的簽名放到redis緩存中,數(shù)據(jù)有效期是1分鐘。這樣每次在驗簽之前先查詢redis緩存中是否有相同的簽名,有即代表這個請求是重復請求,直接攔截

 思路就是這樣,代碼就不寫了

總結

到此這篇關于JAVA實現(xiàn)sm3加密簽名以及防止重復攻擊的文章就介紹到這了,更多相關JAVA sm3加密簽名內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

您可能感興趣的文章:

相關文章

  • selenium高效應對Web頁面元素刷新的實例講解

    selenium高效應對Web頁面元素刷新的實例講解

    今天小編就為大家分享一篇selenium高效應對Web頁面元素刷新的實例講解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-05-05
  • 詳解springboot集成websocket的兩種實現(xiàn)方式

    詳解springboot集成websocket的兩種實現(xiàn)方式

    這篇文章主要介紹了springboot集成websocket的兩種實現(xiàn)方式,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-01-01
  • Java實現(xiàn)一個簡單的緩存方法

    Java實現(xiàn)一個簡單的緩存方法

    本篇文章主要介紹了Java實現(xiàn)一個簡單的緩存方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-04-04
  • Java對日期Date類進行加減運算、年份加減月份加減、時間差等等

    Java對日期Date類進行加減運算、年份加減月份加減、時間差等等

    這篇文章主要介紹了Java對日期Date類進行加減運算、年份加減月份加減、時間差等等,在網上查閱資料,加上自己總結的一些關于Date類的工具類
    2017-01-01
  • java中使用url進行編碼和解碼

    java中使用url進行編碼和解碼

    這篇文章主要介紹了java中使用url進行編碼和解碼,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • springboot maven 項目打包jar 最后名稱自定義的教程

    springboot maven 項目打包jar 最后名稱自定義的教程

    這篇文章主要介紹了springboot maven 項目打包jar 最后名稱自定義的教程,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-10-10
  • Java面向對象之作用域詳細解讀

    Java面向對象之作用域詳細解讀

    這篇文章主要介紹了Java面向對象之作用域詳細解讀,在java編程中,主要的變量就是屬性和局部變量,局部變量一般是指在成員方法中定義的變量,局部變量也就是除了屬性之外的其他變量,作用域為定義他的代碼塊中,需要的朋友可以參考下
    2024-01-01
  • 解決Java包裝類比較時遇到的問題

    解決Java包裝類比較時遇到的問題

    所謂包裝類的作用就是將原始數(shù)據(jù)類型轉換成引用數(shù)據(jù)類型,下面這篇文章主要給大家介紹了關于在Java包裝類比較時遇到的問題的解決方法,文中給出了詳細的示例代碼,需要的朋友可以參考借鑒,下面來一起看看吧。
    2017-09-09
  • java、php、C#、asp實現(xiàn)短信群發(fā)功能的方法

    java、php、C#、asp實現(xiàn)短信群發(fā)功能的方法

    這篇文章主要介紹了java、php、C#、asp實現(xiàn)短信群發(fā)功能的方法,以實例形式較為詳細的分析了java及php、C#、asp、VB.NET等調用短信發(fā)送接口進行短信發(fā)送的功能,需要的朋友可以參考下
    2015-02-02
  • Spring常用注解及自定義Filter的實現(xiàn)

    Spring常用注解及自定義Filter的實現(xiàn)

    這篇文章主要介紹了Spring常用注解及自定義Filter的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-08-08

最新評論

博客| 黄大仙区| 鄂托克旗| 施秉县| 化隆| 聂拉木县| 尉犁县| 泸溪县| 泸州市| 黔东| 晋州市| 凭祥市| 竹北市| 察哈| 离岛区| 历史| 固阳县| 古交市| 吉安县| 灵璧县| 灵丘县| 丘北县| 洞口县| 龙里县| 登封市| 新余市| 景德镇市| 星座| 陆丰市| 霍邱县| 宽甸| 庐江县| 兴海县| 贵阳市| 锦州市| 历史| 霍邱县| 叶城县| 常山县| 县级市| 佛学|