如何防止別人抓包重放攻擊


現在做過幾個web項目,都用到了api,有服務器發往服務器的api,也有微信上從前端發往后端的api。然后,我在使用 Pycharm 斷點時發現,如果在斷點暫停時一直發送請求,那么很多請求都能執行成功。然后在不斷點的正常情況下,我又使用 Charles 重復發送請求,並發設置為10,一共發100個,也有10幾個請求成功了。

前端向后端發送請求

我知道csrf_token可以防止跨站攻擊,但如果現在是一個惡意用戶怎么辦?我有一個每日簽到API,調用之后,在數據庫中添加對應記錄,並增加積分。我先在的校驗方法是,如果數據庫中存在一個今天簽到的記錄,就返回錯誤。現在如果用戶進行請求重放,在數據庫寫入記錄之前發了N條記錄,那么增加積分的操作就會執行N次了。

現在的思路是,看看微信的做法,它的參數中含有 timestamp 和 nonce,並進行了簽名加密。以及 如何防止別人抓包重放攻擊 的一些思路。

一、微信的做法(微信文檔地址

  1. 驗證消息的確來自微信服務器

    通過 timestamp, nonce 以及雙方約定好的 token 構成一個簽名,能夠驗證信息是否來自微信。

    在這里並不適用,因為api就是由用戶調用的。

二、  如何防止別人抓包重放攻擊

  希望一個包就實現, 不是反復發包。

  一個包實現並不僅僅指第一個包實現,可以是前n個失敗,然后第n+1個成功了,然后就拒絕之后的包了。如果需要達成這樣,我們要使能夠實現的請求唯一,構建一個類似id這樣,不能重復的東西。

三、 加鎖

類似雙十一搶購,當一個用戶下單之后,就鎖定5分鍾等待其付款,期間拒絕其他用戶的下單請求。我們能否做到,這個請求期間,針對一個 openid 的請求只進行一次,其他就在后面排隊。當一個成功后,后面類似的請求就看做是失敗的。

有一個同事做過類似的加鎖,明天問問他(沒問,現在在寫新需求以及調優,還沒做這個)。

問了一個同事,建議使用 redis 的 sadd 命令,如果訂單號存在於 set 中,就返回失敗。還有 redis 的分布式鎖,他不建議使用,如果沒有弄清楚分布式鎖的原理。

現在回到我們最初的問題:

如何保證用戶每天只能簽到一次?

獲取簽到請求后,通過唯一值去 redis 中查找,如果存在,則說明簽到過了,返回 "今日已簽到"

不存在,則說明今天還沒有簽到,進行簽到流程。

 

將上面的步驟拆開:

1. 根據用戶的簽到請求構建唯一值

2. 去 redis 中查詢唯一值

3.1 已簽到,拒絕

3.2 未簽到,設置 redis,進行簽到流程

 

問:為什么要儲存在 redis 而不是 mysql 中?

  • 因為儲存到 mysql 中太慢了,

  在儲存到硬盤(mysql)的過程中,這個值是不存在的,若這時候用戶再次發送簽到請求,那么還是可以簽到的。這就違反了"用戶每天只能簽到一次"

 

問:如何將數據保存到 mysql 中?

儲存到 redis 后,使用異步任務將這個數據同步到 mysql。

 

問:如何確保存到 redis 就足夠快?

不確保。我本地測試的時候沒發現能夠多次簽到。

儲存到 redis 的速度大於兩次請求的速度就能夠確保。

 

問:鎖是什么?這個與鎖有什么異同?

 

問:如何查找相關資料?

直接搜索后,找不到很多資料。那么我們就把問題誇大或縮小。

誇大:

搜索`秒殺`

秒殺系統架構分析與實戰

 

問:能否寫一個函數\裝飾器\上下文管理器實現這個功能?

 

問:有沒有相關的第三方庫?

 

服務器向服務器發送api

一般的做法是使用AES加密待發送的內容,再使用RSA加密AES秘鑰,然后將以上兩個一起發送出去。令我感到疑惑的是:為什么需要使用RSA加密AES秘鑰並傳輸,一開始兩邊約定好一個AES秘鑰不就可以了嗎?

所以我現在的做法就是,兩邊約定好AES KEY,然后使用AES加解密內容,並對解密后的內容進行校驗。

 

在一個抽獎功能中又遇到了庫存的問題

需求:存在 N 種不同的抽獎獎品,抽獎的概率與各獎品的實時數量成正比。希望把所有的獎品發放完畢,又不希望超賣。獎品庫存總量變為 0 后,固定返回一種獎品。

比如有3中商品,數量為 A:10, B: 20 C: 70。 則開始時抽中 A 的概率為 (10)/(10+20+70) = 10%,

抽中 A 后, 數量變為 A: 9, B: 20 C: 70,則 A 的概率變為 9 / (9 + 20 + 70)

應用場景:現場抽獎。

 

綜合我的需求與實現難度,決定使用 django transaction + select_for_update 

發現的問題:

select_for_update  只鎖了行,能讀不能寫,會造成超賣;

解決

使用MySQL表鎖

LOCK TABLE business_bankcard READ;
LOCK TABLE business_bankcard WRITE;

# 其他代碼

UNLOCK TABLES;

上面的寫法有問題

LOCK TABLES table_name WRITE;

# 其他代碼

UNLOCK TABLES

因為 WRITE 的含義就是不可讀、不可寫

Option Description
READ Read lock, no writes allowed
READ LOCAL Read lock, but allow concurrent inserts
WRITE Exclusive write lock. No other connections can read or write to this table
LOW_PRIORITY WRITE Exclusive write lock, but allow new read locks on the table until we get the write lock.
WRITE CONCURRENT Exclusive write lock, but allow READ LOCAL locks to the table.

出處:LOCK TABLES and UNLOCK TABLES

 

鎖表的注意事項

注意解鎖

注意異常之后的解鎖

比如捕捉異常后,解鎖,再拋出異常

 

更好的方法

同事建議使用分布式鎖

redis 單機鎖

 

參考: 

如何解決秒殺的性能問題和超賣的討論 

 select for update 帶來的性能問題

測試

如何測試。設置庫存數量后,使用  timesleep 模擬並發的現象

 

參考:

(未看,待整合)Web大規模高並發請求和搶購的解決方案

(從上面這篇文章中可以了解到,要吸收強者的經驗,秒殺與搶購還有比12306和淘寶更多的嗎?看看他們是怎么實現的吧!)

 

日請求從百萬到八億的技術歷程

(規模性的東西還是大公司牛叉)

 

程序員對比在大公司和創業公司的工作和報酬

如果你關心你做某件事后產生的實際效果,在大公司絕對是有更大的實際效果,歸因於大公司的規模。如果我是在一家創業公司做我當前的工作,獲得的收益大約是每月 1 萬美元。我沒什么好蔑視,但這都支付不起我的工資。但是同樣的事情在大公司創造的收益會是1萬美元的1000倍以上。在大公司有更大的實際效果因為它的規模很大。這里的推論是小公司很小以至於他們很容易對自身造成影響,盡管這個影響值本身很小。我感覺不到我做的事情對大公司會產生促進還是阻礙的作用。但是當我在小公司時,看起來我們所做的事情可以影響整個公司的命運。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM