首頁 文章

Solodit 檢查清單解析:拒絕服務攻擊第2部分

2025-04-15

Solodit 檢查表解析(2):拒絕服務攻擊第2部分

了解如何通過確保隊列安全、處理低小數點代幣以及安全管理外部調用來防止智能合約中的拒絕服務(DoS) 攻擊。

歡迎回到“ Solodit 檢查表解析”系列。我們將繼續探索Solodit智能合約審計檢查表,專注於編寫安全且具有彈性的智能合約的實用策略。

該檢查表幫助你識別潛在漏洞並實施主動安全措施。在之前的部分“ Solodit 檢查表解析(1) ”中,我們研究了與拒絕服務(DoS) 攻擊相關的三個檢查項(提取模式、最低交易金額和黑名單),並為開發者提供了解決方案。如果你還沒有閱讀,我建議在繼續之前先查看該文章。

在這篇文章中,我們將討論檢查表中的三個其他項目,再次聚焦於DoS 攻擊。我們將深入探討隊列處理漏洞低小數點代幣帶來的挑戰以及安全處理外部合約調用的重要性

為了獲得最佳體驗,請打開一個Solodit 檢查表的標籤以供參考。

簡要概述

以下是今天我們將討論的內容:

  • SOL-AM-DOSA-4:阻塞隊列處理:當攻擊者操縱隊列以暫停或中斷其操作時,就會出現此問題,從而導致DoS。我們將研究攻擊者如何破壞處理隊列。

  • SOL-AM-DOSA-5:低小數點代幣:處理小數位數低的代幣時會出現的問題。計算,特別是除法,可能會被截斷為零,導致意外且有害的行為。這類低精度代幣可能導致整數除法的問題,從而乾擾關鍵功能。

  • SOL-AM-DOSA-6:不安全的外部調用:我們將探討如何依賴外部合約而沒有適當的錯誤處理創建漏洞。當外部調用的失敗沒有正確處理時,可能導致整個合約發生回滾

現實世界的攻擊證明了這些漏洞可能造成的潛在損害。由於看似微小的疏忽,項目遭受了巨大的損失。

Solodit 檢查表基於審計發現、漏洞賞金報告和現實世界事件。通過研究這些檢查項,你可以從過去的錯誤中學習,改善代碼的安全性

現在,讓我們通過示例代碼逐一查看每個檢查項。這些示例已簡化,以突出核心漏洞。

SOL-AM-DOSA-4:攻擊者能否阻止或防止隊列處理以導致服務中斷?

問題:如果你的智能合約依賴隊列進行任務處理,攻擊者可能會操縱隊列中的特定狀態來阻止正確處理。

檢查表問題:“攻擊者能否阻止或防止隊列處理以導致服務中斷?”

解決方案:你的隊列處理機制需要強大的錯誤處理和回退機制,以確保即使出現問題也能繼續處理。

示例

考慮一個提取隊列的示例:

  1. 用戶請求提取,某些標誌表示請求處於活動狀態。

  2. 攻擊者可以在提取被入隊後利用resetUserStatus函數,阻止其他用戶的同樣操作。

 // 易受攻击的函数:可以被利用function resetUserStatus() external { // 任何人在仍然处于队列中的情况下都可以重置他们的状态withdrawalRequested[msg.sender] = false; // 注意:用户没有被移出队列! } // 处理队列中的下一次提取function processNextWithdrawal() external { require(withdrawalQueue.length > currentIndex, "没有可处理的提取"); // 获取下一次提取Withdrawal memory withdrawal = withdrawalQueue[currentIndex]; // 可被攻击者利用:此检查可能会被重置状态所攻击require(withdrawalRequested[withdrawal.user], "提取请求不再有效"); // 处理提取uint256 amount = withdrawal.amount; require(balances[withdrawal.user] >= amount, "余额不足"); // 更新余额balances[withdrawal.user] -= amount; // 重置提取请求withdrawalRequested[withdrawal.user] = false; // 发送资金(bool success, ) = payable(withdrawal.user).call{value:amount}(""); require(success, "资金发送失败"); // 移动到队列中的下一个currentIndex++; }

要利用這一點,攻擊者可以執行以下操作:

  1. 發起提取請求。
  2. 調用resetUserStatus函數。
  3. processNextWithdrawal函數將回滾,造成持續的DoS 攻擊。

補救措施

  • 限制修改withdrawalRequested狀態的權限給管理員。
  • 確保驗證檢查以避免零值交易。
  • 實施回退函數以處理意外錯誤。

SOL-AM-DOSA-5:低小數點代幣會導致DoS 嗎?

問題:低小數位數的代幣可能導致整數除法問題,從而四捨五入至零

想像一個代幣流媒體合約在一段時間內分配代幣。如果tokensPerSecond由於與低小數點代幣的整數除法而四捨五入為零,分配函數將被阻止。檢查表問題:“低小數點代幣會導致DoS 嗎?”解決方案:實施處理低小數點的邏輯,以防止由於四捨五入錯誤而中斷交易過程。示例

考慮一個TokenStream合約,該合約定期向用戶流送一定數量的代幣,其中:

  1. total_tokens需要轉移到合約
  2. token_per_second可能被四捨五入為零,因為我們使用的是小數點為1的代幣
  3. distributeTokens函數將回滾
contract TokenStream { IERC20 public token; uint256 public streamDuration; uint256 public tokensPerSecond; constructor(IERC20 _token, uint256 _streamDuration, uint256 _tokensPerSecond) { token = _token; streamDuration = _streamDuration; tokensPerSecond = _tokensPerSecond; } function distributeTokens(address recipient) external { uint256 balance = token.balanceOf(address(this)); uint256 amount = tokensPerSecond * streamDuration; uint256 tokensToSend = amount > balance ? balance : amount; require(tokensToSend > 0, "没有足够的代币进行流送"); token.transfer(recipient, tokensToSend); } } contract LowDecimalToken is ERC20 { constructor() ERC20("LowDecimalToken", "LDT") { _mint(msg.sender, 100000 * (10 ** decimals())); } function decimals() public view virtual override returns (uint8) { return 1; // 模拟小数点为低的代币} }

在這種情況下, TokenStreamTest中的testDOSWithLowDecimalTokens測試將會回滾。

補救措施:確保合約正確處理低小數點代幣,通過縮放數學公式來減輕整數四捨五入在計算過程中導致的問題。

SOL-AM-DOSA-6:協議是否安全地處理外部合約交互?

問題:許多智能合約依賴外部合約進行交互。外部合約的意外行為可能導致整個系統回滾。未能處理這些外部錯誤會導致DoS 漏洞。

檢查表問題:“協議是否安全地處理外部合約交互?”

解決方案:確保外部合約交互的強大錯誤處理,以保護協議完整性,無論外部合約的性能如何。

示例:考慮一個與外部Chainlink 價格數據源交互的合約。如果沒有使用try/catch 進行適當的錯誤處理,任何來自外部數據源的回滾將向上級傳播,並導致合約回滾。

  1. getPrice函數檢索價格數據。
  2. 當外部Chainlink 預言機失敗時,整個代碼將回滾。
  3. calculateSomethingImportant函數依賴於getPrice並將也會回滾。
 contract PriceDependentContract { AggregatorV3Interface public priceFeed; constructor(address _priceFeed) { priceFeed = AggregatorV3Interface(_priceFeed); } // 易受攻击的函数,在没有处理可能的Chainlink 回滚的情况下获取价格function getPrice() public view returns (uint256) { (, int256 price, , , ) = priceFeed.latestRoundData(); // 易受攻击的行:没有错误处理require(price > 0, "价格必须为正"); return uint256(price); } function calculateSomethingImportant() public view returns (uint256) { uint256 price = getPrice(); // ... 使用价格的一些重要计算return price * 2; }

補救措施將外部合約調用包裝在try/catch 塊中以處理回滾錯誤,並實施回退或緩存值。

注意:有一個邊緣情況是外部合約故意消耗gas ,這也可能使catch 塊失敗!我們稍後會討論這一點。

結論

我們探討了三個關鍵檢查項,旨在增強你的智能合約抵禦DoS 攻擊的能力:隊列處理漏洞與低小數點代幣相關的挑戰以及安全處理外部合約交互的重要性

請記住,提供的示例旨在說明核心漏洞。理解基本原則並將這些概念調整為你的具體用例是非常重要的。

通過實施這些建議,你可以顯著提高智能合約的安全性和韌性。

請繼續關注“Solodit 檢查表解析”系列的下一部分。

  • 原文鏈接: cyfrin.io/blog/solodit-c...
  • 登鏈社區AI 助手,為大家轉譯優秀英文文章,如有翻譯不通的地方,還請包涵~

最新更新

熱門文章

遊戲推薦

軟體推薦