知识库
返回
explainCKBot·
2 mins
什么是重入攻击?它如何运作?

重入攻击是区块链中最危险的攻击类型之一。

cover

重入攻击(reentrancy attack)是指黑客在智能合约中的某个易受攻击函数尚未完成第一次执行时,反复调用该函数,从而抽走资金,或以非预期的方式操纵合约状态。

2016 年的 The DAO 攻击事件让重入攻击广为人知。那次事件导致价值数百万美元的 ETH 被盗,最终引发了一次备受争议的硬分叉。

智能合约:区块链逻辑的基础

智能合约是存在于以太坊、Solana、Nervos CKB 等区块链上的自执行代码。它包含预先定义的逻辑,无须中介即可自动执行约定。

例如,设想一份替线上储蓄小组保管资金的智能合约。规则可能是:“任何人都可以存入 ETH,并在以后取出。”听起来很简单。

问题在于,智能合约不会像人一样思考。它会严格按照代码逐行执行。哪怕只有一个小错误,或者漏掉一个步骤,也可能有人利用这个弱点,让合约出现意料之外的行为。

重入攻击正是如此:它利用合约处理指令的方式发动攻击。

重入攻击如何运作

重入攻击利用的是时序,具体来说,是合约执行操作的先后顺序。以一个类似数字银行的简单智能合约为例,用户可以存入和提取 ETH。典型的提款流程可能如下:

  1. 合约检查用户余额是否充足。
  2. 合约将用户请求的 ETH 发送给用户。
  3. 合约更新用户余额。

乍看之下,这很合理。但危险恰恰来自步骤的顺序。在上面的例子中,智能合约先发送 ETH,再更新余额。这个微小的错误为重入攻击打开了入口。

黑客可以这样利用它:

  • 黑客创建另一份能与银行合约交互的合约,并向银行存入一些 ETH,比如 1 ETH。

  • 黑客提款时,其合约会“监听”转回的资金。ETH 刚开始转入,黑客的合约就在余额更新之前,迅速再次调用银行合约。

  • 银行合约认为黑客仍有 1 ETH 可提取,于是再次发送。

  • 这个过程不断重复,直到银行的钱包被掏空。

这是一种巧妙的手法,整个过程只需几秒。

漏洞不在以太坊协议,而在合约逻辑。关键是正确安排顺序:在转移资金之前更新状态,就能防止重入。然而,多年来,无数合约都犯过先执行外部调用、后更新内部状态的错误,因而容易成为攻击目标。

The DAO 攻击:区块链历史上的惨痛教训

2016 年的 The DAO 攻击仍是最著名的重入攻击案例。

The DAO(全称为“Decentralized Autonomous Organization”,即去中心化自治组织)是运行在以太坊上、由社区管理的去中心化风险投资基金。人们可以向其中投入 ETH,对项目投票,合约会自动为通过投票的项目提供资金。高峰时期,The DAO 持有约 1,270 万 ETH,当时价值约 1.5 亿美元,是历史上规模最大的众筹项目之一。

但 The DAO 的代码中隐藏着一个漏洞,正是前面讨论的那种:合约在更新余额之前发送资金。

攻击者发现这个缺陷后,编写了一份合约,在 The DAO 来得及记录资金已转出之前,反复调用其“withdraw”函数。短短数小时内,黑客就抽走了 360 万 ETH,约占整个基金的三分之一。

事件严重到引发了以太坊区块链的一次争议性硬分叉,将其分成两个独立版本。一个版本,也就是今天的以太坊,逆转了攻击结果,退还了被盗资金。另一个版本 Ethereum Classic 保留了原始、未经修改的历史,以体现区块链的不可篡改性。

为什么加密领域重视重入攻击

重入攻击备受关注的原因很简单:它造成的损失真实存在,而且往往具有毁灭性。加密货币历史上一些最著名的攻击,就源于这一特定类型的漏洞。

如今,重入攻击仍是开发者和审计人员最关心的问题之一,因为它利用了可组合金融的特性。在 DeFi 中,协议就像相互连接的乐高积木。一份合约可能向另一份合约借款,在第三份合约中交易代币,再使用第四份合约计算价格。这种可组合性(composability)推动了创新,也带来了共同风险。一份有漏洞的合约可能被无数其他合约调用,让一次漏洞利用在整个生态中蔓延。

跨链桥(cross-chain bridges)的兴起又增添了一层复杂性。跨链桥连接不同区块链,让资产可以在网络间转移。如果桥的一侧存在重入漏洞,攻击者可能触发跨链反复发生的递归交易,扩大损害。

旨在提高交易速度、降低费用的 Layer 2 方案也面临类似风险。其智能合约通常依赖与主链的交互,任何时机或执行顺序上的不匹配,都可能为新的漏洞利用打开入口。

开发者如何防止重入攻击

防止重入攻击,首先要理解它如何产生。最广泛接受的智能合约开发原则称为“检查—状态更新—交互”(checks-effects-interactions)模式。

这种设计方式要求合约先执行所有必要检查,例如验证余额或权限,然后更新内部状态,记录提款已发生,最后才与外部实体交互,例如发送代币或进行外部调用。在与合约外部交互前完成内部更新,就能消除攻击者利用重入的机会。

另一种常见防御方式是使用重入保护(reentrancy guard),它就像函数上的锁。函数开始执行时,锁随即启用,阻止任何新的调用,直到函数执行结束。执行完成后,锁再打开。

安全审计和测试至关重要。如今,许多区块链项目会付费聘请独立专家检查合约漏洞,也有工具可以自动扫描可能导致重入问题的代码模式。

结语

重入攻击听起来可能是复杂的技术问题,但其核心其实是时序和逻辑:智能合约在检查是否仍应付款之前,就先付出了资金。

重入攻击的历史,尤其是最初的 The DAO 事件,不仅是一则警示,也提醒我们:即使面对最先进的技术,人对细节的关注仍然最为重要。

end