1. 程式人生 > 其它 >WEB安全新玩法 [10] 防範競爭條件支付漏洞

WEB安全新玩法 [10] 防範競爭條件支付漏洞

「業務安全動態加固平臺 · 實踐系列」

伺服器端業務邏輯,特別是涉及資料庫讀寫時,存在著關鍵步驟的時序問題,如果設計或程式碼編寫不當就可能存在競爭條件漏洞。攻擊者可以利用多執行緒併發技術,在資料庫的餘額欄位更新之前,同時發起多次兌換積分或購買商品請求,從中獲取利益。本文將討論如何簡單地使用 iFlow 應用安全加固平臺的可程式設計特性,對競爭條件產生的支付漏洞進行防護。

一、原始網站

這是一個在支付環節存在競爭條件漏洞的站點:使用者輸入一個支付數值,系統將這個數值與餘額比較,如果支付數值小於餘額則允許支付,並從餘額中減去支付數值。

攻擊者編寫並執行了一個 Python 攻擊指令碼,使用多執行緒併發對支付請求 URL 進行訪問。由於未能正確處理競爭條件問題,系統為多個請求同時扣除了餘額。我們回到瀏覽器中重新整理頁面,可以發現餘額變為了 -10

元,如下圖所示。

HTTP 互動流程如下:

sequenceDiagram participant 攻擊者 participant 瀏覽器 participant 攻擊工具 participant Web伺服器 participant 資料庫 攻擊者->>瀏覽器: 點選“競爭條件-支付”連結 瀏覽器->>Web伺服器: GET /race_condition/pay.php 資料庫->>Web伺服器: 讀取金額 Web伺服器->>瀏覽器: 返回“競爭條件-支付”頁面 瀏覽器->>攻擊者: 顯示:餘額為10元 攻擊者->>攻擊工具: 執行多執行緒併發請求 rect rgb(250, 128, 128) 攻擊工具->>Web伺服器: POST /race_condition/pay.php Web伺服器->>資料庫: 餘額足夠,扣除支付金額 攻擊工具->>Web伺服器: POST /race_condition/pay.php Web伺服器->>資料庫: 餘額足夠,扣除支付金額 攻擊工具->>Web伺服器: POST /race_condition/pay.php Web伺服器->>資料庫: 餘額足夠,扣除支付金額 end 攻擊者->>瀏覽器: 點選“競爭條件-支付”連結 瀏覽器->>Web伺服器: GET /race_condition/pay.php 資料庫->>Web伺服器: 讀取金額 Web伺服器->>瀏覽器: 返回“競爭條件-支付”頁面 瀏覽器->>攻擊者: 顯示:餘額為-4元

二、iFlow虛擬補丁後的網站

我們在 Web 伺服器前部署 iFlow 業務安全加固平臺,它有能力攔截、計算和修改雙向 HTTP 報文並具備儲存能力,成為 Web 應用的虛擬補丁。本例中,iFlow 使用一個全域性唯一的定時標誌來阻止對併發請求的同時處理。

每個支付請求到來時,iFlow 都會檢查定時標誌是否存在。只有標誌不存在時才交給 Web 伺服器處理這個請求,並同時設定定時標誌。在定時期間,如有其他支付請求到來,而 iFlow 檢查到定時標誌存在,則會放棄處理這個請求,將使用者重定向到指定頁面。定時結束後,系統則又可以處理下一個支付請求。

HTTP 協議互動過程如下:

sequenceDiagram participant 攻擊者 participant 瀏覽器 participant 攻擊工具 participant iFlow participant Web伺服器 participant 資料庫 攻擊者->>瀏覽器: 點選“競爭條件-支付”連結 瀏覽器->>Web伺服器: GET /race_condition/pay.php 資料庫->>Web伺服器: 讀取金額 Web伺服器->>瀏覽器: 返回“競爭條件-支付”頁面 瀏覽器->>攻擊者: 顯示:餘額為10元 攻擊者->>攻擊工具: 執行多執行緒併發請求指令碼 攻擊工具->>iFlow: POST /race_condition/pay.php Note over iFlow: 設定定時標誌 iFlow->>Web伺服器: POST /race_condition/pay.php Web伺服器->>資料庫: 餘額足夠,扣除支付金額 rect rgb(250, 128, 128) 攻擊工具->>iFlow: POST /race_condition/pay.php end Note over iFlow: 定時標誌存在,重定向頁面 rect rgb(250, 128, 128) 攻擊工具->>iFlow: POST /race_condition/pay.php end Note over iFlow: 定時標誌存在,重定向頁面 攻擊工具->>iFlow: POST /race_condition/pay.php Note over iFlow: 定時標誌超時後不存在 iFlow->>Web伺服器: POST /race_condition/pay.php Web伺服器->>資料庫: 餘額不足,不執行支付 攻擊者->>瀏覽器: 點選“競爭條件-支付”連結 瀏覽器->>Web伺服器: GET /race_condition/pay.php 資料庫->>Web伺服器: 讀取金額 Web伺服器->>瀏覽器: 返回“競爭條件-支付”頁面 瀏覽器->>攻擊者: 顯示:餘額為0元

程式碼

iFlow 內建的 W2 語言是一種專門用於實現 Web 應用安全加固的類程式語言。它介於配置和通用語言之間,具備程式設計的基本要素和針對 HTTP 協議的特有擴充套件,能為業務系統編寫涉及複雜判斷和動態修改的邏輯。

考慮到安全產品的使用者通常為非程式設計師,他們習慣面對配置檔案而非一段程式碼。因此,W2 語言雖包含語言要素,仍以規則檔案方式呈現,並採用可以體現層次結構和方便詞法校驗的 JSON 格式。

用 W2 語言實現上述虛擬補丁的程式碼如下:

{
	"if": [
		"REQUEST_FILENAME == '/race_condition/pay.php'",
		"REQUEST_METHOD == 'POST'"
	],
    "then": {
		"if": "GLOBAL.pay_time_flag",
		"then": {
			"verdict": {
				"action": "redirect",
                "param": "/retry.html"
			}
		},
		"else": "GLOBAL.pay_time_flag@2=1"
    }
}

示例程式碼中,當伺服器端收到支付請求時,iFlow 攔截此請求。iFlow 會檢查全域性 (GLOBAL) 儲存變數 pay_time_flag 是否存在:如存在,則重定向到頁面 /retry.html (向正常使用者提示稍後重試);如不存在,則設定一個生命時長為2秒 (數值可根據實際請求處理所需時間調整) 的儲存變數 pay_time_flag

注意:上述會話中的 pay_time_flag 是儲存在伺服器端的 iFlow 儲存中的,攻擊者在瀏覽器端是看不到資料更無法進行修改的。

三、總結

使用 iFlow 書寫一條規則,即可實現在設定時間內只允許處理一個請求,避免競爭條件帶來的異常處理。(張戈 | 天存資訊)