關於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
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...