一、什麼是重放攻擊?
我們在開發介面的時候通常會考慮介面的安全性,比如說我們通常會要求請求的url攜帶一個經過演算法加密的簽名sign
到服務端進行驗證,如果驗證通過,證明請求是合法的。比如以下的url:
http://wokao66.com/in.json?uid=7&sign=xxxxx
其中sign
的常用加密演算法為MD5
,MD5
演算法是一種不可逆演算法,也就是說你加密之後就不能解密了。這通常要求通訊雙方約定好一個私鑰appSecret
,這個私鑰是約定好的,不能在網路上進行傳輸。但單單有這個加密是遠遠不夠的,比如說我是一名黑客,我抓包了你當前執行成功的請求資訊,我們假設為request-1
,既然你都執行成功了,也就是說你的這次請求的所有引數都是合法的,那麼作為黑客的我,我就想能不能將你request-1
的請求資料再封裝成另外一個請求request-2
,然後再去請求介面,如果此時系統未作任何處理,那麼系統肯定是認為request-2
是合法的,肯定還是會放行,但至於業務上成不成功,那麼是另外一個問題了,倘若在執行業務前需要進行一個相對耗時的資料庫操作,那麼大量的request-2
,request-3
勢必會使伺服器癱瘓。
醬紫,可能語言難以理解,我畫個圖先:
首先正常的請求系統會要求校驗,當你的合法請求被黑客攔截之後,黑客就會重複地傳送該合法請求,從而達到欺騙系統的目的!這種重複利用合法請求進行攻擊成為重放。
二、如何防止重放攻擊?
重放攻擊的原理其實很簡單,無非就是系統沒有對合法請求進行唯一性校驗
。什麼意思呢?就是說系統要知道你第一次的合法請求request-1
不能被重複執行,要保證每次請求的唯一性。那麼怎麼去防止重放攻擊呢?
參考網路上的解決方案,大概有以下兩種方式:
- 1、採用時間戳
這種方式的做法就是,首先我們認為一次HTTP請求從發出到到達伺服器的時間是不會超過60s的,當你傳送一個請求時必須攜帶一個時間戳timestamp
,假設值為10,當請求到達伺服器之後,伺服器會取出當前時間,假設為t2=80,很明顯t2-timestamp>60s
,那麼伺服器就認為請求不合法。
號外號外,這個時間戳是需要加入MD5
加密簽名的,不然黑客修改了時間戳t2=20
,那不就是白費功夫了。
為什麼這樣做有效?
首先黑客從抓包到發起請求一般會超過60s,再者我們不需擔心黑客修改了時間戳timestamp
,因為如果修改了時間戳,那麼對應的簽名sign
也就失效了,因為MD5
是不可逆的,你想偽造MD5
,必須知道雙方約定的金鑰appSecret
。
缺點:
- 如果黑客在60s內發起攻擊,那麼我們就束手無策了。
- 2、採用時間戳 + 隨機數
nonce
上面說到時間戳是有缺點的,那麼我們加入一個隨機數nonce
,每次成功請求,伺服器會儲存當前成功請求的隨機數nonce
,比如存放在redis
和資料庫中,當請求再次進到伺服器,先驗證時間戳是否有效,如果有效,再判斷攜帶的隨機數nonce
是否在快取或者資料庫中已經存在,如果存在,則認為請求非法。
但你會發現,如果系統請求非常多,這個存放nonce
的快取也好,資料庫也好勢必會越來越大,那麼我們只需要儲存伺服器當前時間60秒內的nonce
值即可。
缺點:
- 你得保證隨機數
nonce
絕對唯一
- 3、基於
record
的方案
什麼是基於record
的驗證方式呢?就是說我現在不需要隨機數,我利用MD5加密的唯一性,採用多維度(多個欄位),將每次請求的記錄儲存到資料庫中,每次請求先校驗簽名記錄是否存在,如果存在,則認為請求非法,不存在,則將MD5
簽名結合其他引數一起儲存到資料庫中。當然這裡也可以結合時間戳只儲存60s內的資料。
第三點主要是不考慮採用隨機數機制,同時對自己業務可以有不同的擴充套件,或者說加入業務引數方便運維監控等。
綜合上面幾種方案,都有缺點,其中一個致命的缺點是伺服器的時間和客戶端的時間是存在時間差的,當然你也可以通過校驗時間戳解決此問題。
謝謝閱讀。