主页 > imtoken最新版官网 > 防止对以太坊的智能合约攻击——代码分析
防止对以太坊的智能合约攻击——代码分析
以太坊智能合约的一个特点是能够调用和使用来自其他外部合约的代码。
合约通常也处理以太币,并经常将以太币发送到各种外部用户地址。 这些操作需要合约提交外部调用。 这些外部调用可能会被攻击者劫持,攻击者可以强制合约执行更多代码(通过回退函数),包括对自身的调用。
臭名昭著的 DAO 攻击中使用了这种类型的攻击。
了解漏洞
当合约将以太币发送到未知地址时,就会发生这种类型的攻击。 攻击者可以在回退函数中小心地在包含恶意代码的外部地址上构建合约。
因此,当一个合约向这个地址发送以太币时,它会调用恶意代码。 通常,恶意代码会在易受攻击的合约上执行一个功能,该功能会执行开发人员不希望做的事情。
“重入”一词来源于此:外部恶意合约调用易受攻击合约上的函数,代码执行路径“重新进入”它。
为了澄清这一点,将易受攻击的 EtherStore.sol 视为一个以太坊金库,储户每周只能提取 1 个以太币:
以太坊.sol
该合约有两个公共函数,depositFunds 和 withdrawFunds。
depositFunds 函数只是增加发送方的余额。
withdrawFunds 函数允许发送者指定要提取的 wei。
仅当请求提取的金额少于 1 个以太币并且上周没有发生任何提款时,此功能才会成功。
错误在第 17 行,合约向用户发送了他们想要的以太币数量。
考虑一个在 Attack.sol 中创建合约的攻击者:
攻击.sol
漏洞是如何发生的?
首先,攻击者会使用EtherStore的合约地址作为唯一的构造函数参数来创建恶意合约(假设地址为0x0...123)。 这将初始化并将公共变量 etherStore 指向要攻击的合约。
然后,攻击者将使用大于或等于 1 的以太币调用 attackEtherStore 函数——让我们现在假设 1 个以太币。
在这个例子中,我们还假设许多其他用户已经将以太币存入这个合约以太坊智能合约漏洞,所以它的当前余额是 10 个以太币。 然后会发生以下情况:
Attack.sol 的第 15 行:EtherStore 的 depositFunds 函数将为 1 个以太币(和大量气体)调用 msg.value。 发件人 (msg.sender) 将是恶意合约 (0x0...123)。 因此以太坊智能合约漏洞,balances[0x0..123] = 1 个以太币。
Attack.sol第17行:恶意合约会调用EtherStore合约的withdrawFunds函数,参数为1个以太币。 这将通过所有要求(EtherStore 合约的第 12-16 行),因为之前没有提款。
EtherStore.sol 的第 17 行:将向恶意合约发送 1 个以太币。
Attack.sol第25行:支付给恶意合约的款项将执行回退功能。
Attack.sol 的第 26 行:EtherStore 合约的总余额是 10 个以太币,现在是 9 个以太币,所以这个 if 语句通过了。
Attack.sol第27行:再次调用EtherStore的withdrawFunds函数,“重新进入”EtherStore合约。
EtherStore.sol 的第 11 行:在第二次调用 withdrawFunds 时,攻击合约的余额仍然是 1 个以太币,因为第 18 行还没有执行。 所以我们还有。 lastWithdrawTime 变量也是如此。 我们再次通过了所有要求。
的第 17 行:攻击合约并再拿走 1 个以太币。
重复步骤 4-8,直到 Attack.sol 不再出现,如第 26 行所示。
Attack.sol 的第 26 行:一旦 EtherStore 合约中剩下 1 个(或更少)以太币,这个 if 语句就会失败。 这将允许执行 EtherStore 合约的第 18 行和第 19 行(对于每次调用 withdraw 函数)。
EtherStore.sol,第 18 和 19 行:将设置 balance 和 lastwithdraw 映射并结束执行。
最终结果是,攻击者在一次交易中从 EtherStore 合约中提取了除 1 个以太币以外的所有以太币。
预防技术
有一些常用技术可以帮助避免智能合约中潜在的重入漏洞。
第一个是(在可能的情况下)在将以太币发送到外部合约时使用内置的传输功能。 转账函数通过外部调用只发送了2300 gas,不足以让目的地址/合约调用另一个合约(即重新进入发送合约)。
第二种技术是确保所有更改状态变量的逻辑都发生在以太币被发送出合约(或任何外部调用)之前。 在 EtherStore 示例中,EtherStore.sol 的第 18 和 19 行应放在第 17 行之前。
对于任何对未知地址进行外部调用的代码,最好将此作为本地化函数或代码执行部分中的最后一个操作。 这就是所谓的检查-效果-交互模式。
第三种技术是引入互斥量——即添加一个状态变量,在代码执行期间锁定合约,防止重入调用。
将所有这些技术应用于 EtherStore(没有必要同时使用这三种技术,但我们这样做是为了演示目的),给出了一个不可重入的合约:
以太坊.sol
讲故事的时间
DAO(去中心化自治组织)攻击是以太坊早期发展中发生的主要黑客攻击之一。
当时,该合同价值超过 1.5 亿美元。 重入在攻击中发挥了重要作用,最终导致了创建以太坊经典 (ETC) 的硬分叉。