使用nonce鞏固介面簽名安全

技術小能手發表於2018-12-03

前面我們有講過如何進行API的安全控制,其中包括資料加密,介面簽名等內容。詳細可以參考我下面兩篇文章:

《前後端API互動如何保證資料安全性》

《再談前後端API簽名安全?》

在簽名部分,通過時間戳的方式來判斷當前請求是否有效,目的是為了防止介面被多次使用。但是這樣並不能保證每次請求都是一次性的,今天給大家介紹下如何保證請求一次性?

首先我們來回顧一些時間戳判斷的原理:客戶端每次請求時,都需要進行簽名操作,簽名中會加上signTime引數(當前請求時間戳)。HTTP請求從發出到達伺服器的正常時間不會很長,當伺服器收到HTTP請求之後,首先進行簽名檢查,通過之後判斷時間戳與當前時間相比較,是否超過了一定的時間,這個時間我們可以自行決定要多長,比如1分鐘,2分鐘都可以,時間長點可以防止客戶端和伺服器時間不一致的問題,如果超過了則認為是非法的請求。

假設我們的請求有效期是1分鐘,如果黑客得到了我們的請求地址,在1分鐘之內是可以重複請求多次的,因為這種方式不能保證請求僅一次有效。

基於nonce的方式可以解決重複使用的問題,最開始知道nonce是在廣點通的介面中看到的,如下圖所示:

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1.png

可以看到騰訊這邊的介面也是基於時間戳和nonce來控制的。

nonce是隨機字串,每次請求時都要保證不同,你可以用uuid,可以用別的演算法,也可以用隨機加時間戳等等,只要不重複就行。

在後端我們驗證的時候,將nonce引數儲存起來,至於是儲存在本地記憶體中,資料庫中,redis,布隆過濾器中這就看你自己的需求了。

處理HTTP請求時,首先判斷該請求的nonce引數是否在存在,如果存在則認為是非法請求。如果不存在則是合法請求,讓後將該nonce儲存起來,防止下次重複使用。

這種方式的弊端也很明顯,那就是nonce的儲存會越來越大,驗證nonce是否存在的時間會越來越長。

如何解決儲存問題?

可以用時間戳+nonce同時使用,相互配合,取長補短。

首先我們根據時間戳判斷是否超過了一定的時間範圍,如果超過了就直接拒絕,沒有超過繼續驗證nonce是否使用過。

nonce沒使用,儲存起來,記錄一個儲存時間,通過定時任務去清除超過了時間戳驗證的時間的nonce。這樣的話我們只需要儲存固定時間內的nonce資料,因為時間長的已經被時間戳的判斷給攔截了,nonce的驗證只需要驗證時間有效期內的即可。

虛擬碼如下:

// 1.1獲取簽名時間,跟當前時間做對比,判斷是否超出範圍
Long signTime = 1XXXXL;
Long curTime = System.currentTimeMillis();
if (curTime - signTime > 60000) {
    // 超出了
    return;
}

// 1.2獲取nonce判斷是否存在,以redis舉例
String nonce = "XXXXXX";
if (redisTemplate.hasKey(nonce)){
    //已經使用過了
else {
    //沒有使用,儲存起來,設定過期時間為當前訪問時間+判斷請求過期的時間
    //這樣就不用定時任務去清除之前的nonce,利用redis自動清除
   redisTemplate.opsForValue().set(nonce, ""1, TimeUnit.MINUTES);
}
原文釋出時間為:2018-12-03
本文作者:尹吉歡
本文來自雲棲社群合作伙伴“猿天地”,瞭解相關資訊可以關注“
猿天地”。


相關文章