防止重復請求攻擊
今天發(fā)現(xiàn)自己項目一個漏洞:先為一賬戶充值100元,然后瞬間發(fā)送10次提現(xiàn)請求(都是提現(xiàn)100,提現(xiàn)接口是有做余額不足校驗的),其中大約有四五次都是成功的,剩下的會報余額不足。期望是,只有一次可以成功完成提現(xiàn),分析到能部分請求能通過余額不足校驗原因是,由于是瞬間發(fā)出的提現(xiàn)請求,這些請求中拿到的余額數(shù)據(jù)都是余額扣減之前的數(shù)據(jù)。
以上場景可以提煉出兩個關鍵步驟:
- 查詢余額并校驗,select * from account where user_id = 123;
- 扣減余額并支付,update account set balance...
根據(jù)以上步驟,可知:1.在兩條SQL語句執(zhí)行的中間這段時間,由于重復請求攻擊,可能會出現(xiàn)多次請求的第一步操作成功,并繼續(xù)執(zhí)行第二步,最后導致資金損失。2.由于第一步操作是查詢操作,沒有數(shù)據(jù)庫會限制重復讀取數(shù)據(jù),數(shù)據(jù)庫層面是沒有可能解決這個問題的,所以不用在這個上面浪費時間。
目前的解決方案是:為接口上鎖。已經(jīng)有人做了輪子,比如redis-lock。以用戶ID為key,某個uuid為值。將類似提現(xiàn)這樣的接口上鎖。同一用戶在訪問添加了該中間件的接口時,第一次沒有執(zhí)行完畢,拒絕執(zhí)行第二個請求。第一次執(zhí)行完畢時,釋放鎖,即清除redis緩存的鍵值對。同時可設定,緩存時長,以防中途宕機,鎖未釋放等問題。具體實現(xiàn)可以參考npm包redis-lock文檔。
查資料不過是偏門,擼源碼才是脫離苦海的正道。

浙公網(wǎng)安備 33010602011771號