相關鏈接:
http://www.cnblogs.com/ziyi--caolu/p/4742577.html
請求防重放:http://www.2cto.com/kf/201612/573045.html
登錄防重放:http://huangqiqing123.iteye.com/blog/2033014
一、概念和定義
1、什么是重放攻擊?
我們在設計接口的時候,最擔心一個接口被別有用心的用戶截取后,用於重放攻擊。重放攻擊是什么呢?就是把請求被原封不動地重復發送,一次,兩次...n次。
2、重放攻擊造成的后果
一般的請求被提交到后台執行,先會經過【頁面驗證】后提交給【后台邏輯】,提交給【后台邏輯】過程中請求可能會被被攔截,
- 如果這個【后台邏輯】是插入數據庫操作,就很容易造成多條重復的數據插入數據庫。
- 如果這個【后台邏輯】是查詢數據庫操作,就可能導致反復查詢,數據庫被堵住等情況。
所以,我們需要一種防重放的機制來做請求驗證。
二、解決方案
1、客戶端(攜帶timestamp+nonce)
我們常用的防止重放的機制是使用timestamp和nonce來做的重放機制。
1.1、timestamp
timestamp用來表示請求的當前時間戳,這個時間要事先和服務器時間戳校正過。我們預期正常請求帶的時間戳會是不同的,如:假設正常人每秒至多會做一個操作。
每個請求攜帶的時間戳不能和當前時間距離很近,即不能超過規定時間,如60s。這樣請求即使被截取了,也只能在有限時間(如:60s)內進行重放,過期就會失效。
1.2、nonce
僅僅提供timestamp還是不夠的,我們還是提供給攻擊者60s的可攻擊時間了。要避免60秒內發生攻擊,我們還需要使用一個nonce隨機數。
nonce是由客戶端根據隨機生成的,比如 md5(timestamp+rand(0, 1000),正常情況下,在短時間內(比如60s)連續生成兩個相同nonce的情況幾乎為0。
2、服務端(驗證時間是否超限,檢查簽名)
服務端第一次在接收到這個nonce的時候做下面行為:
1 去redis中查找是否有key為nonce:{nonce}的string
2 如果沒有,則創建這個key,把這個key失效的時間和驗證timestamp失效的時間設置一致,比如是60s。
3 如果有,說明這個key在60s內已被使用過了,這個請求就可以判斷為重放請求。
3、方案流程
http://www.xxxx.com?userId=123&userName=zhangsan×tamp=1480556543&nonce=43f34f33&sign=80b886d71449cb33355d017893720666
在這個請求中,userId和userName是真正需要傳遞的業務參數,timestamp,nonce,sign都是為了簽名和防重放使用。
timestamp是發送請求時間,nonce是隨機串,sign是對uid,timestamp,nonce(對於一些rest風格的api,建議業務參數一起簽名)。
服務端接到這個請求的處理邏輯:
- 先驗證sign簽名是否合理,證明請求參數沒有被中途篡改
- 再驗證timestamp是否過期,證明請求是在最近60s被發出的
- 最后驗證nonce是否已經有了,證明這個請求不是60s內的重放請求
4、方案分析
我們將每次請求的nonce參數存儲到一個“集合”中,可以json格式存儲到緩存中。
每次處理HTTP請求時,首先判斷該請求的nonce參數是否在該“集合”中,如果存在則認為是非法請求。
我們在timestamp方案的基礎上,加上nonce參數,因為timstamp參數對於超過60s的請求,都認為非法請求,所以我們只需要存儲60s的nonce參數的“集合”即可。
nonce的一次性可以解決timestamp參數60s的問題,timestamp可以解決nonce參數“集合”越來越大的問題。