開發(fā)解決方案 ● 如何解決重復(fù)下單的問(wèn)題?(下單防重,重放攻擊)

問(wèn)題來(lái)源:

近日發(fā)現(xiàn)某些用戶對(duì)一些商品進(jìn)行多次下單,而且比較頻繁,而且下單時(shí)間都在同一秒內(nèi),懷疑產(chǎn)生重復(fù)請(qǐng)求

問(wèn)題描述:

用戶在商品頁(yè)面,多次點(diǎn)擊下單按鈕,后臺(tái)怎么知道是用戶對(duì)一個(gè)商品進(jìn)行多次下單,還是人工誤操作或者客戶端異常進(jìn)行重復(fù)請(qǐng)求下單了呢?

解決方案:

  1. 進(jìn)入商品頁(yè)面,就是下單頁(yè)面的時(shí)候,產(chǎn)生一個(gè)不重復(fù)的隨機(jī)數(shù)。
  2. 下單的時(shí)候把這個(gè)隨機(jī)數(shù)帶上
  3. 下單校驗(yàn)的時(shí)候,利用Redis緩存鎖,先鎖這個(gè)隨機(jī)數(shù),再做業(yè)務(wù)處理,做完再釋放。

問(wèn)題升級(jí):

如果客戶端重復(fù)的下單請(qǐng)求過(guò)多,或者后臺(tái)處理過(guò)快,就會(huì)產(chǎn)生所謂的重放攻擊。
如,客戶端請(qǐng)求模擬
請(qǐng)求A 20:18:01 xxx/order?storeid=1&randomNum=abcd123 用戶下單
請(qǐng)求A 獲得鎖成功,開始處理
請(qǐng)求B 20:18:01 xxx/order?storeid=1&randomNum=abcd123 用戶下單
請(qǐng)求B 獲得鎖失敗
請(qǐng)求C 20:18:01 xxx/order?storeid=1&randomNum=abcd123 用戶下單
請(qǐng)求C 獲得鎖失敗
請(qǐng)求A 下單成功,釋放鎖
請(qǐng)求D 20:18:01 xxx/order?storeid=1&randomNum=abcd123 用戶下單
請(qǐng)求D 獲得鎖成功,開始處理
請(qǐng)求D 下單成功,釋放鎖

針對(duì)同一個(gè)隨機(jī)數(shù)randomNum=abcd123居然下單成功2次,這就是重復(fù)攻擊帶來(lái)的危害

問(wèn)題升級(jí),解決方案:

  1. 下單校驗(yàn)的時(shí)候,利用Redis緩存鎖,先鎖這個(gè)隨機(jī)數(shù),鎖成功之后,判斷隨機(jī)數(shù)是否曾經(jīng)處理過(guò),如果沒(méi)有就把隨機(jī)數(shù)加入緩存設(shè)置時(shí)長(zhǎng)為X,再做業(yè)務(wù)處理,做完再釋放。

關(guān)鍵代碼

/**
     * 獲得鎖
     * @param lockId
     * @return
     */
    public boolean getLock(String lockId) {
        try {

            String KEY_LOCK_ID_="LOCK_ID_";
            String KEY_LOCK_HIS_ID_="LOCK_HIS_ID_";
            Boolean success = redisTemplate.opsForValue().setIfAbsent(KEY_LOCK_ID_+lockId, "lock");
            //解決重放攻擊
            if(success != null && success){
              if(hasKey(KEY_LOCK_HIS_ID_+lockId)){
                  success = false;
                  logger.error("【REDIS操作】【獲得鎖失敗】【已存在歷史鎖碼】【懷疑重放攻擊:"+lockId+"】");
              }else{
                  success = true;
                  set(KEY_LOCK_HIS_ID_+lockId,lockId,60*60*24);
              }
            }
            return success;
        } catch (Exception e) {
            logger.error("【REDIS操作】【獲得鎖錯(cuò)誤】",e); 
            return false;
        }
    }

    /**
     * 釋放鎖
     * @param lockId
     */
    public void releaseLock(String lockId) {
        try {
            String KEY_LOCK_ID_="LOCK_ID_";
            redisTemplate.delete(KEY_LOCK_ID_ + lockId);
        } catch (Exception e) {
            logger.error("【REDIS操作】【釋放鎖錯(cuò)誤】",e); 
        }
    }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • #0 系列目錄# 秒殺系統(tǒng)架構(gòu) 秒殺系統(tǒng)架構(gòu)分析與實(shí)戰(zhàn) #1 秒殺業(yè)務(wù)分析# 正常電子商務(wù)流程 (1)查詢商品;(...
    Java架構(gòu)師Carl閱讀 1,648評(píng)論 0 8
  • 一、編程規(guī)約 (一)命名規(guī)約 【強(qiáng)制】 代碼中的命名均不能以下劃線或美元符號(hào)開始,也不能以下劃線或美元符號(hào)結(jié)束。反...
    喝咖啡的螞蟻閱讀 1,610評(píng)論 0 2
  • 阿里巴巴 JAVA 開發(fā)手冊(cè) 1 / 32 Java 開發(fā)手冊(cè) 版本號(hào) 制定團(tuán)隊(duì) 更新日期 備 注 1.0.0 阿...
    糖寶_閱讀 7,889評(píng)論 0 5
  • 今天已經(jīng)2019年1月3號(hào)了,拖延到今天才開始寫總結(jié),著實(shí)有些不應(yīng)該。2017年畢業(yè)到現(xiàn)在已經(jīng)一年半了,17年的時(shí)...
    努力與幸運(yùn)閱讀 294評(píng)論 0 0
  • 依舊沉浸在假期里的自己不得不面對(duì)開學(xué)的現(xiàn)實(shí),或許開始上班忙起來(lái)自己就不會(huì)胡思亂想,于我而言是一個(gè)好的消息。 學(xué)生面...
    木子的碎碎念閱讀 303評(píng)論 2 5

友情鏈接更多精彩內(nèi)容