服務器端業務邏輯,特別是涉及數據庫讀寫時,存在着關鍵步驟的時序問題,若是設計或代碼編寫不當就可能存在競爭條件漏洞。攻擊者能夠利用多線程併發技術,在數據庫的餘額字段更新以前,同時發起屢次兌換積分或購買商品請求,從中獲取利益。本文將討論如何簡單地使用 iFlow 應用安全加固平臺的可編程特性,對競爭條件產生的支付漏洞進行防禦。php
1、原始網站
這是一個在支付環節存在競爭條件漏洞的站點:用戶輸入一個支付數值,系統將這個數值與餘額比較,若是支付數值小於餘額則容許支付,並從餘額中減去支付數值。html
攻擊者編寫並執行了一個 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元
2、iFlow虛擬補丁後的網站
咱們在 Web 服務器前部署 iFlow 業務安全加固平臺,它有能力攔截、計算和修改雙向 HTTP 報文並具有存儲能力,成爲 Web 應用的虛擬補丁。本例中,iFlow 使用一個全局惟一的定時標誌來阻止對併發請求的同時處理。編程
每一個支付請求到來時,iFlow 都會檢查定時標誌是否存在。只有標誌不存在時才交給 Web 服務器處理這個請求,並同時設置定時標誌。在定時期間,若有其餘支付請求到來,而 iFlow 檢查到定時標誌存在,則會放棄處理這個請求,將用戶重定向到指定頁面。定時結束後,系統則又能夠處理下一個支付請求。json
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 存儲中的,攻擊者在瀏覽器端是看不到數據更沒法進行修改的。
3、總結
使用 iFlow 書寫一條規則,便可實如今設定時間內只容許處理一個請求,避免競爭條件帶來的異常處理。(張戈 | 天存信息)