当前位置:首页 > 物联网 > 区块链
[导读] 即将于12月初推出的伊斯坦布尔硬分叉包括EIP1884:“限制trie大小有关的操作码”。关键字是“限制”,这意味着某些指令现在将花费更多的气体来执行。最近对此进行了很多讨论的原因是现有的可以少

即将于12月初推出的伊斯坦布尔硬分叉包括EIP1884:“限制trie大小有关的操作码”。关键字是“限制”,这意味着某些指令现在将花费更多的气体来执行。最近对此进行了很多讨论的原因是现有的可以少量气体运行代码,硬分叉后可能超过该限制,并导致会出现“out of gas”错误。

“以少量气体运行代码”的一个特例是任何Solidity智能合约中的fallback函数,因为它是由Solidity的transfer函数或Solidity和Vyper的send函数触发的以太坊传递过程中运行的代码。transfer和send都只允许以太坊的接收者以2300的气体(实际上是零)。伊斯坦布尔到分叉后,接近此限制的fallback函数可能会停止工作,而任何调用这些函数的智能合约都将在有限的气体中停止工作。

出于安全原因,到目前为止,推荐使用transfer和send来传输Ether。它们所允许的气体不足以进行重入攻击,因此有论据认为,它将保护智能合约免受它们的侵害。确实有……但是以太坊开发者社区现在正面临这样一个现实,即操作码定价不能被认为是稳定的,并且如果我们希望构建面向未来的系统,我们应该寻求其他确保安全的方法。即我们应该停止使用transfer,而转而使用其他发送以太网的方法,而应依赖其他安全技术来防止重入攻击。

本文介绍了可重入性,目前可用于根据它获得智能合约的技术,以及如何使用OpenZeppelin合约轻松在项目中实现它们。特别值得一提的是我们还没有提到的一种技术:提款支付法(pull payments)。

什么是可重入攻击?

智能合约在正常执行期间可以通过执行函数调用或简单地转移以太坊来执行对其他智能合约的调用。这些智能合约本身可以称为其他智能合约。特别是它们可以回调到调用他们的智能合约或回调栈中的任何其他智能合约。在这种情况下,我们说智能合约被重新输入,这种情况被称为可重入性。

重入本身不是问题。当智能合约以“不一致”状态重新输入时,就会出现问题。当智能合约特定的不变量成立时,状态被认为是一致的。例如对于ERC20主要不变性是所有智能合约余额的总和不超过已知的总供应量。

通常函数假定它们开始运行时便以一致的状态观察智能合约,并且它们还承诺一旦完成运行就使智能合约保持一致。在执行过程中,可能会违反不变量,这很好,只要没有人能观察到不一致的状态。问题在于通过重入,这成为可能。函数完成时,不仅要保持不变量,还必须在每个潜在的重入点保持不变。

当我们调用不受信任的智能合约或将资金转入不受信任的帐户时,我们的代码容易受到重入攻击的攻击。可以对这些帐户进行特殊编程,以在重入调用期间滥用不变违规。

这里的不变之处在于,智能合约中的资金额等于余额映射中所有条目的总和。在第三行执行调用期间,由于_amount资金已转出,但余额尚未更新,因此不变量被破坏了。 由于msg.sender可以是智能合约,因此同一调用允许重入。 如果攻击者此时触发了重入,他们将能够从破碎的不变量中获利。

function withdraw(uint _amount) public {

if (amount 《= balances[msg.sender]) {

msg.sender.call.value(_amount)();

balances[msg.sender] -= _amount;

}

}

现在,我们将看到几种抵御这些攻击的方法。

Checks-Effects-InteracTIons(检查-效果-交互)

我们应该提到的第一种技术称为Checks-Effects-InteracTIons模式。 它描述了一种在函数中组织语句的方法,以使智能合约的状态在调出其他智能合约之前处于一致的状态。通过将每个语句分类为检查,效果(状态更改)或交互作用,并确保严格按照此顺序进行操作来完成此操作。通过在交互之前放置效果,我们可以确保所有状态更改都在任何潜在的重入点之前完成,从而使状态保持一致。

已经对这种模式进行了很多讨论,您应该在Solidity文档中和ConsenSys的最佳实践中对其进行阅读。

但是我们应该对这种方法不满意,因为它容易受到人为错误的影响:程序员必须正确地应用它,而审阅者必须发现任何错误。是否可以减轻穷人的这种责任?

ReentrancyGuard(重入保护)

如果在执行的任何时候不确定智能合约的不变量是否成立,则应避免调用其他(不可信)智能合约,因为它们可能会被重入。 如果我们别无选择,可以尝试使用ReentrancyGuard来防止可重入。

ReentrancyGuard(重入保护)是一段代码,当检测到重入时,该执行会导致执行失败。OpenZeppelin合约中有一个称为ReentrancyGuard(重入保护)的模式实现,该模式提供了nonReentrant修饰符。将此修饰符应用于函数将使其变为“不可重入”,并且通过重新调用将拒绝重新输入该函数的尝试。

当我们的智能合约具有多个函数时会发生什么? 由于修饰符是针对每个函数的应用,因此如果要完全防止重入攻击,则必须将其应用于所有函数。否则如果它对不可变的变量很敏感,仍然有可能重新进入另一个函数并将其用于重入攻击。

但是如果我们决定使每个函数都nonReentrant,则应牢记Solidity的public变量。标记为public的合约变量将生成一个getter函数以读取其值,并且无法对该函数应用修饰符。在大多数情况下,这不会引起重入问题,但仍然值得担心,因为它可能会导致其他合约由于不可变而导致状态不一致的情况(假设它们会保留)。

尽管有所有注意事项,但在某些情况下,重入防护(reentrancy guards)可能会很有价值。但是要完全消除可重入性也有其弊端:在某些情况下,可重入性是安全的,并且随着以太坊智能合约变得更加复杂,可组合和相互联系,我们可能会在外看到它的合法用途。

Pull Payments(提款支付法)

如果我们将Ether转移到合约中但未执行其代码,则根本无法重入。通过使用selfdestruct,可以在EVM中绕过接收器的代码。但是接收以太币的合约需要以某种方式进行处理,并且大多数没有编程为处理通过自毁而收到的资金,这可能导致资金损失。

另一种选择是提款支付模式(pull payment )。这个想法是与其将资金“推”到接收者,不如将它们“拉”出合约。 OpenZeppelin合约在PullPayment合约中实现了这种模式。继承此协定将提供类似于传递的内部函数_asyncTransfer。但是它不会将资金发送给接收方,而是将其转移到托管合约中。此外PullPayment还为接收者提供Public函数以提取其付款:withdrawPayments和withdrawPaymentsWithGas。

OpenZeppelin Contracts 2.4中添加了第二个命令withdrawPaymentsWithGas,以修复伊斯坦布尔的操作码重新定价,并在实际的以太坊转移过程中将所有可用的气体转发给接收器。请注意此时可以重新输入,但这是安全的,因为PullPayment(提款支付法)不会使您的合约的任何不变式无效。

值得一提的是,提款功能可以由任何人调用,而不仅仅是接收方。这意味着收款人无需知道这是预付款的目标,这在现有的智能合约无法自行付款时尤其重要。

总 结

由于操作码定价不稳定,我们不能再依赖转移了,因此在后伊斯坦布尔世界中,重入变得不可避免。攻击者可以将其用于破坏状态不变性时调用不信任帐户的合约。有必要通过根据checks-effects-interacTIons模式组织代码,或使用诸如ReentrancyGuard(重入保护)措施或Pull Payments(提款支付法)等工具来对我们的合约进行编程,以防止重入攻击。

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: 驱动电源

在工业自动化蓬勃发展的当下,工业电机作为核心动力设备,其驱动电源的性能直接关系到整个系统的稳定性和可靠性。其中,反电动势抑制与过流保护是驱动电源设计中至关重要的两个环节,集成化方案的设计成为提升电机驱动性能的关键。

关键字: 工业电机 驱动电源

LED 驱动电源作为 LED 照明系统的 “心脏”,其稳定性直接决定了整个照明设备的使用寿命。然而,在实际应用中,LED 驱动电源易损坏的问题却十分常见,不仅增加了维护成本,还影响了用户体验。要解决这一问题,需从设计、生...

关键字: 驱动电源 照明系统 散热

根据LED驱动电源的公式,电感内电流波动大小和电感值成反比,输出纹波和输出电容值成反比。所以加大电感值和输出电容值可以减小纹波。

关键字: LED 设计 驱动电源

电动汽车(EV)作为新能源汽车的重要代表,正逐渐成为全球汽车产业的重要发展方向。电动汽车的核心技术之一是电机驱动控制系统,而绝缘栅双极型晶体管(IGBT)作为电机驱动系统中的关键元件,其性能直接影响到电动汽车的动力性能和...

关键字: 电动汽车 新能源 驱动电源

在现代城市建设中,街道及停车场照明作为基础设施的重要组成部分,其质量和效率直接关系到城市的公共安全、居民生活质量和能源利用效率。随着科技的进步,高亮度白光发光二极管(LED)因其独特的优势逐渐取代传统光源,成为大功率区域...

关键字: 发光二极管 驱动电源 LED

LED通用照明设计工程师会遇到许多挑战,如功率密度、功率因数校正(PFC)、空间受限和可靠性等。

关键字: LED 驱动电源 功率因数校正

在LED照明技术日益普及的今天,LED驱动电源的电磁干扰(EMI)问题成为了一个不可忽视的挑战。电磁干扰不仅会影响LED灯具的正常工作,还可能对周围电子设备造成不利影响,甚至引发系统故障。因此,采取有效的硬件措施来解决L...

关键字: LED照明技术 电磁干扰 驱动电源

开关电源具有效率高的特性,而且开关电源的变压器体积比串联稳压型电源的要小得多,电源电路比较整洁,整机重量也有所下降,所以,现在的LED驱动电源

关键字: LED 驱动电源 开关电源

LED驱动电源是把电源供应转换为特定的电压电流以驱动LED发光的电压转换器,通常情况下:LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: LED 隧道灯 驱动电源
关闭