http://www.7klian.com

以太坊伊斯坦布尔之后的重入进攻问题

已经对这种模式举办了许多接头,您应该在Solidity文档中和ConsenSys的最佳实践中对其举办阅读。
假如在执行的任何时候不确定智能合约的稳定量是否创立,则应制止挪用其他(不行信)智能合约,因为它们大概会被重入。 假如我们别无选择,可以实验利用ReentrancyGuard来防备可重入。

重入自己不是问题。当智能合约以“纷歧致”状态从头输入时,就会呈现问题。当智能合约特定的稳定量创立时,状态被认为是一致的。譬喻对付ERC20主要稳定性是所有智能合约余额的总和不高出已知的总供给量。
可是我们应该对这种要领不满足,因为它容易受到工钱错误的影响:措施员必需正确地应用它,而审阅者必需发明任何错误。是否可以减轻穷人的这种责任?
“以少量气体运行代码”的一个特例是任何Solidity智能合约中的fallback函数,,因为它是由Solidity的transfer函数或Solidity和Vyper的send函数触发的以太坊通报进程中运行的代码。transfer和send都只答允以太坊的吸收者以2300的气体(实际上是零)。伊斯坦布尔到分叉后,靠近此限制的fallback函数大概会遏制事情,而任何挪用这些函数的智能合约都将在有限的气体中遏制事情。
此刻,我们将看到几种抵制这些进攻的要领。
我们应该提到的第一种技能称为Checks-Effects-Interactions模式。 它描写了一种在函数中组织语句的要领,以使智能合约的状态在调出其他智能合约之前处于一致的状态。通过将每个语句分类为查抄,结果(状态变动)或交互浸染,并确保严格凭据此顺序举办操纵来完成此操纵。通过在交互之前安排结果,我们可以确保所有状态变动都在任何潜在的重入点之前完成,从而使状态保持一致。
  }

如安在伊斯坦布尔硬分叉之后掩护你的智能合约不被重入进攻。

假如我们将Ether转移到合约中但未执行其代码,则基础无法重入。通过利用selfdestruct,可以在EVM中绕过吸收器的代码。可是吸收以太币的合约需要以某种方法举办处理惩罚,而且大大都没有编程为处理惩罚通过自毁而收到的资金,这大概导致资金损失。
Pull Payments(提款付出法)

智能合约在正常执行期间可以通过执行函数挪用或简朴地转移以太坊来执行对其他智能合约的挪用。这些智能合约自己可以称为其他智能合约。出格是它们可以回调到挪用他们的智能合约或回调栈中的任何其他智能合约。在这种环境下,我们说智能合约被从头输入,这种环境被称为可重入性。

凡是函数假定它们开始运行时便以一致的状态调查智能合约,而且它们还理睬一旦完成运行就使智能合约保持一致。在执行进程中,大概会违反稳定量,这很好,只要没有人能调查到纷歧致的状态。问题在于通过重入,这成为大概。函数完成时,不只要保持稳定量,还必需在每个潜在的重入点保持稳定。
尽量有所有留意事项,但在某些环境下,重入防护(reentrancy guards)大概会很有代价。可是要完全消除可重入性也有其漏洞:在某些环境下,可重入性是安详的,而且跟着以太坊智能合约变得越发巨大,可组合和彼此接洽,我们大概会在外看到它的正当用途。
出于安详原因,到今朝为止,推荐利用transfer和send来传输Ether。它们所答允的气体不敷以举办重入进攻,因此有论据认为,它将掩护智能合约免受它们的侵害。确实有……可是以太坊开拓者社区此刻正面对这样一个现实,即操纵码订价不能被认为是不变的,而且假如我们但愿构建面向将来的系统,我们应该寻求其他确保安详的要领。即我们应该遏制利用transfer,而转而利用其他发送以太网的要领,而应依赖其他安详技能来防备重入进攻。

function withdraw(uint _amount) public {
  if (amount <= balances[msg.sender]) {
本文先容了可重入性,今朝可用于按照它得到智能合约的技能,以及如何利用OpenZeppelin合约轻松在项目中实现它们。出格值得一提的是我们还没有提到的一种技能:提款付出法(pull payments)。
ReentrancyGuard(重入掩护)
另一种选择是提款付出模式(pull payment )。这个想法是与其将资金“推”到吸收者,不如将它们“拉”出合约。 OpenZeppelin合约在PullPayment合约中实现了这种模式。担任此协定将提供雷同于通报的内部函数_asyncTransfer。可是它不会将资金发送给吸收方,而是将其转移到托管合约中。另外PullPayment还为吸收者提供Public函数以提取其付款:withdrawPayments和withdrawPaymentsWithGas。
当我们挪用不受信任的智能合约或将资金转入不受信任的帐户时,我们的代码容易受到重入进攻的进攻。可以对这些帐户举办非凡编程,以在重入挪用期间滥用稳定违规。
}
OpenZeppelin Contracts 2.4中添加了第二个呼吁withdrawPaymentsWithGas,以修复伊斯坦布尔的操纵码从头订价,并在实际的以太坊转移进程中将所有可用的气体转发给吸收器。请留意此时可以从头输入,但这是安详的,因为PullPayment(提款付出法)不会使您的合约的任何稳定式无效。

什么是可重入进攻?

值得一提的是,提款成果可以由任何人挪用,而不只仅是吸收方。这意味着收款人无需知道这是预付款的方针,这在现有的智能合约无法自行付款时尤其重要。
ReentrancyGuard(重入掩护)是一段代码,当检测到重入时,该执行会导致执行失败。OpenZeppelin合约中有一个称为ReentrancyGuard(重入掩护)的模式实现,该模式提供了nonReentrant修饰符。将此修饰符应用于函数将使其变为“不行重入”,而且通过从头挪用将拒绝从头输入该函数的实验。

    balances[msg.sender] -= _amount;
即将于12月初推出的伊斯坦布尔硬分叉包罗EIP1884:“限制trie巨细有关的操纵码”。要害字是“限制”,这意味着某些指令此刻将耗费更多的气体来执行。最近对此举办了许多接头的原因是现有的可以少量气体运行代码,硬分叉后大概高出该限制,并导致会呈现“out of gas”错误。
由于操纵码订价不不变,我们不能再依赖转移了,因此在后伊斯坦布尔世界中,重入变得不行制止。进攻者可以将其用于粉碎状态稳定性时挪用不信任帐户的合约。有须要通过按照checks-effects-interactions模式组织代码,或利用诸如ReentrancyGuard(重入掩护)法子或Pull Payments(提款付出法)等东西来对我们的合约举办编程,以防备重入进攻。

这里的稳定之处在于,智能合约中的资金额便是余额映射中所有条目标总和。在第三行执行挪用期间,由于_amount资金已转出,但余额尚未更新,因此稳定量被粉碎了。 由于msg.sender可以是智能合约,因此同一挪用答允重入。 假如进攻者此时触发了重入,他们将可以或许从破碎的稳定量中赢利。
总       结
Checks-Effects-Interactions(查抄-结果-交互)

郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。

相关文章阅读