SWC-113/失败调用引发的DoS攻击
外部呼叫可能会偶然或故意失败,从而引发合约出现DoS。为了最大程度地减少此类故障造成的损害, 最好将每个外部呼叫隔离到自己的交易中,该交易可以由呼叫的接收者发起。这与支付特别相关, 在这种情况下,最好让用户提取资金,而不是自动将资金推送到他们(这也减少了gaslimit出现问题的机会)。
CWE漏洞分类
整改方案
建议遵循调用合约的最佳做法:
- 避免在单一交易中合并多个调用,尤其是当调用作为循环的一部分执行时
- 始终假设外部呼叫可能失败
- 实现失败调用的处理逻辑
参考文献
示例合约
send_loop.sol
/*
* @source: https://consensys.github.io/smart-contract-best-practices/known_attacks/#dos-with-unexpected-revert
* @author: ConsenSys Diligence
* Modified by Bernhard Mueller
*/
pragma solidity 0.4.24;
contract Refunder {
address[] private refundAddresses;
mapping (address => uint) public refunds;
constructor() {
refundAddresses.push(0x79B483371E87d664cd39491b5F06250165e4b184);
refundAddresses.push(0x79B483371E87d664cd39491b5F06250165e4b185);
}
// bad
function refundAll() public {
for(uint x; x < refundAddresses.length; x++) { // arbitrary length iteration based on how many addresses participated
require(refundAddresses[x].send(refunds[refundAddresses[x]])); // doubly bad, now a single failure on send will hold up all funds
}
}
}
send_loop.yaml
description: Send called in a loop
issues:
- id: SWC-113
count: 1
locations:
- bytecode_offsets:
'0x0740310f63ff97d41fdc9170b44535586a824d54c710dd0e9f75d7103bf71ce8': [431]
line_numbers:
send_loop.sol: [21, 22, 23]