關於web資金系統提現安全保護,防止極快的重覆併發請求導致重覆提現的解決思路

来源:https://www.cnblogs.com/zyczyc/archive/2019/03/04/10470589.html
-Advertisement-
Play Games

關於WEB金融系統中的提現安全問題很多人沒有深入思想,導致有漏洞,常常會遇到有些人遇到被攻擊到導資金損失的麻煩, 其實要徹底解決重覆併發請求 導致重覆提現問題,是需要花點心思的,並沒有看起來的那麼 簡單,即使是最直觀簡單的語句都是有漏洞的比如: 場景1 發現很多朋友的項目一個漏洞:先為一賬戶充值10 ...


關於WEB金融系統中的提現安全問題很多人沒有深入思想,導致有漏洞,常常會遇到有些人遇到被攻擊到導資金損失的麻煩,     其實要徹底解決重覆併發請求 導致重覆提現問題,是需要花點心思的,並沒有看起來的那麼 簡單,即使是最直觀簡單的語句都是有漏洞的比如:

-----------------------------------------場景1--------------------

發現很多朋友的項目一個漏洞:先為一賬戶充值100元,然後瞬間發送10次提現請求(都是提現100,提現介面是有做餘額不足校驗的),其中大約有四五次都是成功的,剩下的會報餘額不足。期望是,只有一次可以成功完成提現,分析到能部分請求能通過餘額不足校驗原因是,由於是瞬間發出的提現請求,這些請求中拿到的餘額數據都是餘額扣減之前的數據。

以上場景可以提煉出兩個關鍵步驟:

  1. 查詢餘額並校驗,select * from account where user_id = 123;
  2. 扣減餘額並支付,update account set balance...

根據以上步驟,可知:1.在兩條SQL語句執行的中間這段時間,由於重覆請求攻擊,可能會出現多次請求的第一步操作成功,並繼續執行第二步,最後導致資金損失。2.由於第一步操作是查詢操作,沒有資料庫會限制重覆讀取數據

-----------------------------------------場景2----------------------------------

重覆提交,錶面上是重覆提交,威力不大,但實際。。。我們來分析分析:
假設一個用戶,餘額100,平臺恰好有個提現的地方,理所當然用戶最多只能提取100元。
我們來分析下程式在生成提現數據的過程:
開啟事務;
用戶發起一次提現請求,到達應用後,程式判斷用戶餘額是否夠用,如果不夠就跳出事務了;
然後扣除100元,
然後再提現數據表中插入一條數據,
到這裡還沒結束,因為事務還沒提交,當上面進行順利時,到達這裡就應該commit提交了,如果上面操作任何一步異常,就rollback回滾了。
看起來挺完美的過程,其實!弱暴了!
為啥?
假如用戶發起兩個請求,而且同一時間(1/1000秒級)請求到伺服器,
再走一次上面的邏輯:
請求一達到伺服器 請求二達到伺服器
開啟事務 開啟事務
餘額檢查->通過 餘額檢查->通過
扣除餘額->done 扣除餘額->done
插入提現記錄->done 插入提現記錄->done
提交->commit(); 提交->commit();
兩邊幾乎同時進行一樣的操作,為什麼沒被攔截掉只處理一個請求呢?因為餘額檢查時,別的請求的事務未提交,在此請求內select的數據還未生效,所以兩個請求處理都通過了檢查。
那怎麼防禦呢?
token?
扯J8蛋!token用來防禦這原子級別的攻擊?別說session了,即使你重寫php底層,讓session動態調用php的記憶體也無濟於事。原因自己腦補;
隊列是終極解決方案。
然後有一個臨時方案,提現的表中肯定會有time/datetime之類的欄位,在建表時將這個表中的time/datetime + userId 設置為聯合主鍵,然後事務在插入提現數據時,因為時間同一秒且同一用戶所以數據衝突,只會成功一條,然後事務報錯啟動回滾,近乎完美。唯一的瑕疵就是假如前後誤差1ms, 然後恰好前一個時間是xxxx1,後一個時間是xxxx2,這樣就扯痛蛋了。。。千分之一的概率。

-----------------------------------------原因-----------------------------------

有人人甚至認為無解 ,其實是對資料庫理解不夠深,如事務級別(臟讀,讀提交,不可重覆讀,序列化級,快照級,)、併發機制、鎖(共用鎖,更新鎖,X獨占鎖,行級鎖,頁級鎖、意向鎖),這麼多底層知識有足夠的理解才能解決這個問題,因為這些方便資料很少,願意花精力去研究的人更不多,更鬱悶的是微軟資料庫對查詢作了優化,文檔和實際執行效果是不一樣的,比如微軟文檔明文寫著,共用鎖 與更新鎖是可以相關排斥的,select語句預設是發佈hold共用鎖,如果你真信就完了,你實際執行結果是共用鎖和updlock不會排斥,除非你顯示指定,select * from  account with(holdlock)  文檔和實際不一致,只有遇到坑後請求微軟技術支持才他技術人員才知道你,微軟對select做了特別優勢預設不是被排斥很多鎖的,瞬間被坑,當年還記有個攜程的主程式員不懂鎖亂用,給一個查詢加了with(nolock), 訂票資金出現重大事故教訓。 所以我提供以下幾個常用的解決方法。不是不可能其實也很簡單。

數據在資料庫層面解決這個問題很簡單,反相用了ORM EntityFramework之類的才不好解決資料庫解決方案
解決方案1:使用顯示事務

begin tran
select * from account with(rowlock updlock) where user_id = 123; --發佈行級更新鎖,第二併發請求到這裡嚴格排序,不管有多快,這裡有個技巧,因為第二個併發撞進來第一句也是updlock所以兩個updlock之間會排斥
update account set balance...
commit

 


解決方案2:在代碼層使用分佈事務

using (TransactionScope ts = new TransactionScope()) //用這個需要本地單獨開MSDTC (Distributed Transaction Coordinator)服務,並不一定通用 有門檻
{
exesql("update account set balance=balance where user_id =123"); //這一句很重要,事務中開頭一句update讓資料庫先發佈一個x鎖,後面的併發將被嚴格排隊
exesql("select * from account where user_id = 123;");
exesql("update account set balance..");
ts.Complete();
}

 


方案3 ,在代碼入口使用線程鎖

public static object lockObj =new object();
public void Withdraw(int user_id,int amount){
  lock (lockObj){ //讓提現操作線上程線嚴格排序,不管併發有多快,缺點是不同的用戶 提現也得按順序排序,但一般提現操作是小概率操作,不會很密集,正常提現的沒阻塞感知,但是攻擊者可以反覆發起請求,導致正確用戶提現變慢或阻塞
    exesql("select * from account where user_id = 123;");
    exesql("update account set balance..");

  }
}

 一個很重要的技巧是在一個事務內,第一句先 寫一個無意義的update  Account with(rowlock)   set  balance=balance where userid=123  ; 這個技巧在任何時候都適用,強制讓資料庫在事務期內發佈x級獨占行級鎖鎖,後面的操作被嚴格排隊,就算攻擊者重覆請求也只會阻塞他自己的用戶查詢,不會阻塞別人的


總結:最可行的是存儲過程方案1,缺點是不靈活,在如今ORM滿天飛的情況下新一代人很少有會寫存儲過程SQL了,
方案2,是一個折中方案,一般可控性還好
方案3,使用最簡單,基本是零成本,零難度,但是會有潛被拒絕服務攻擊的功能,但保證最重要的數據安全

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1、增增加目錄命令:mkdir 映射--1.新建目錄名為dir1 eg:mkdir dir1 2.一次建多個文件夾eg:temp1,temp2,temp3 mkdir temp1 temp2 temp3 3.新建父目錄,文件已存在也不會報錯; eg:mkdir -p t1/t2/t3增加文件命令:t ...
  • 背景:從軟通出來,告別華為外包,離開H區,進入了一家搞大數據的創業公司,感覺周圍都好陌生,記錄下自己大數據的career! 2019-03-4新的徵程-入職第一天: 一、辦理入職手續 公司人比較少,沒有入職培訓等操作;用了企業微信和企業郵箱,填下個人信息,然後開搞; 二、搭建Java開發環境和虛擬機 ...
  • 今天在調試使用ansible進行標準化安裝MySQL8.0時,發現關於caching_sha2_password plugin的一個bug。 在搭建主從複製時,按照手冊說明需要創建用戶: 然後在從庫執行: 悲催的是,發現從庫的IO_Thread提示連不上主庫。 而如果在從庫上直接使用mysql命令行 ...
  • 1:主鍵和外鍵的定義 主鍵(primary key):一列(或一組列),其值能夠唯一區分表中每個行 。外鍵(foreign key) 外鍵為某個表中的一列,它包含另一個表的主鍵值,定義了兩個表之間的關係 借用其他博客中的三個數據表解析一下: 2:是哪個表的外鍵? 以上面的成績表為例,學號和課程號是成 ...
  • 筆記記錄自林曉斌(丁奇)老師的《MySQL實戰45講》 8.a) --事務到底是隔離還是不隔離的? 這部分內容不太容易理解,筆者也是進行了多次閱讀。因此引用原文: 之前有提到過,如果是在可重覆讀隔離級別,事務T啟動的時候會創建一個視圖read-view,之後事務T執行期間,即使有其他事務修改了數據, ...
  • 很多人都知道MySQL忘記root密碼之後可以通過skip-grant-tables來暫時免密登錄MySQL,從而修改root密碼,但是這種方式一方面有安全隱患,另一方面也並不怎麼適用於Windows系統,今天在通過此方式修改MySQL8.0 on Windows的root密碼時遇到了這個問題,寫個 ...
  • 首先配置web.config,使配置文件連接access資料庫: <connectionStrings> <add name="DBConnection" connectionString="Provider=Microsoft.Jet.Oledb.4.0;Data Source=|DataDire ...
  • 正文 MySQL的explain命令語句提供瞭如何執行SQL語句的信息,解析SQL語句的執行計劃並展示,explain支持select、delete、insert、replace和update等語句,也支持對分區表的解析。通常explain用來獲取select語句的執行計劃,通過explain展示的 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...