SWC-128/利用区块gas限制的DoS攻击
部署智能合约或调用智能合约中的函数时,根据完成这些合约需要多少计算量,执行这些操作 始终需要一定数量的gas。以太坊网络指定了区块gas限制上限,并且区块中包含的所有交易的 总和不能超过该阈值。
在中心化应用程序中无害的编程模式,当执行功能的成本超过区块限制时,也可能会导致智能合约 中的服务拒绝。例如修改大小未知的数组,当数组变大后,就会导致拒绝服务的情况。
CWE漏洞分类
整改方案
建议谨慎使用可能随时间而增长很大的数组。应避免在整个数据结构中循环的操作。
如果必须遍历未知大小的数组,则应计划它可能占用多个块,因此需要进行多个交易。
参考文献
示例合约
dos_address.sol
pragma solidity ^0.4.25;
contract DosGas {
address[] creditorAddresses;
bool win = false;
function emptyCreditors() public {
if(creditorAddresses.length>1500) {
creditorAddresses = new address[](0);
win = true;
}
}
function addCreditors() public returns (bool) {
for(uint i=0;i<350;i++) {
creditorAddresses.push(msg.sender);
}
return true;
}
function iWin() public view returns (bool) {
return win;
}
function numberCreditors() public view returns (uint) {
return creditorAddresses.length;
}
}
dos_address.yaml
description: DoS Gas Limit reached when trying to empty the array of addresses for winning the game
issues:
- id: SWC-128
count: 1
locations:
- bytecode_offsets:
'0x53aef779087c1829c3990fbf300aaafe4ccbd3328e8b6a630c7484b8c921aa8e': [408]
line_numbers:
dos_address.sol: [10]
dos_number.sol
pragma solidity ^0.4.25;
contract DosNumber {
uint numElements = 0;
uint[] array;
function insertNnumbers(uint value,uint numbers) public {
// Gas DOS if number > 382 more or less, it depends on actual gas limit
for(uint i=0;i<numbers;i++) {
if(numElements == array.length) {
array.length += 1;
}
array[numElements++] = value;
}
}
function clear() public {
require(numElements>1500);
numElements = 0;
}
// Gas DOS clear
function clearDOS() public {
// number depends on actual gas limit
require(numElements>1500);
array = new uint[](0);
numElements = 0;
}
function getLengthArray() public view returns(uint) {
return numElements;
}
function getRealLengthArray() public view returns(uint) {
return array.length;
}
}
dos_number.yaml
description: DoS Gas Limit in array empty and optionally in for loop
issues:
- id: SWC-128
count: 1
locations:
- bytecode_offsets: {}
line_numbers:
dos_number.sol: [29]
dos_simple.sol
pragma solidity ^0.4.25;
contract DosOneFunc {
address[] listAddresses;
function ifillArray() public returns (bool){
if(listAddresses.length<1500) {
for(uint i=0;i<350;i++) {
listAddresses.push(msg.sender);
}
return true;
} else {
listAddresses = new address[](0);
return false;
}
}
}
dos_simple.yaml
description: DoS Gas Limit reaches when try to empty the array of addresses
issues:
- id: SWC-128
count: 1
locations:
- bytecode_offsets: {}
line_numbers:
dos_simple.sol: [16]