重大事件
The DAO 攻击:让以太坊一分为二的重入漏洞(2016 年 6 月)
2016 年 6 月 17 日 The DAO 攻击如何发生:splitDAO 中的递归调用漏洞、被抽走的 360 万枚 ETH、7 月 20 日区块 1,920,000 的硬分叉,以及以太坊经典的诞生。
2016 年 6 月 17 日,攻击者利用 The DAO 的 splitDAO 函数中的重入漏洞,把约 364 万枚 ETH——约占该基金三分之一、按当时价格约 6,000 万美元——抽进一个子合约。以太坊的回应是在 2016 年 7 月 20 日于区块 1,920,000 执行硬分叉,追回资金,也让网络永久分裂为以太坊与以太坊经典。
1. The DAO:一个没有管理者的 1.5 亿美元投资基金
- 事件背景: 2016 年,以太坊上线仅九个月,正在寻找第一个有分量的应用。由 Christoph Jentzsch、其兄 Simon 与 Stephan Tual 创立的德国公司 Slock.it 公布了一份去中心化风险基金的代码:代币持有者把以太币汇集起来,提出项目、投票决定资助对象,没有董事,也没有司法辖区。
- 事件详情: The DAO 的众筹从 2016 年 4 月 30 日持续到 5 月 28 日,从约 11,000 名参与者手中募得约 1,270 万枚 ETH——约占当时流通以太币的 14%,按当时价格约 1.5 亿美元,成为当时史上规模最大的众筹。出资者按比例获得 DAO 代币。
- 技术架构创新:
- 写进合约里的治理: 提案、投票权重和资金释放全部由 Solidity 代码处理。这个组织只以公链上的字节码形式存在——这既是它的全部要义,事后看也是它的全部问题。
- 作为逃生舱的 split 函数: 不认同某项资助决定的少数派可以调用 splitDAO,带着按比例分得的以太币分裂成一个「子 DAO」,但需经过 27 至 28 天的创建窗口才能提款。漏洞就藏在这道安全阀里。
- 直接影响: 一份智能合约一度持有堪比中型风险基金的资金,却没有法律实体、没有保险,也无法给已部署的代码打补丁。
- 长期意义:
- 警告是公开的,也是被忽视的: 2016 年 5 月 27 日,Dino Mark、Vlad Zamfir 与 Emin Gün Sirer 发表《呼吁对 The DAO 实施临时暂停》,指出多项治理与机制设计缺陷。另外,包括 Peter Vessenes 在内的开发者在 6 月初就撰文讨论过 Solidity 合约中的递归调用漏洞。
- 一种在失败中存活下来的范式: DAO 作为组织形式并没有消失,如今已有数千个,而 2016 年之后建成的工具链,默认要防的正是这一次暴露出的失效模式。
- 经验教训: 把代码公开、指望社区来审计,并不等于审计——尤其当「找 bug 的截止时间」就是资金到账的那一刻。
- 后续发展: 2017 年 7 月 25 日,美国 SEC 发布报告,认定 DAO 代币在美国法律下属于证券,这是其首次就基于区块链的发行正式适用证券法。
2. 2016 年 6 月 17 日:攻击
- 事件背景: The DAO 的以太币躺在一份任何人都能调用的合约里。攻击者有备而来:提前数日部署了恶意合约,并购入 DAO 代币,使自己成为合法参与者。
- 事件详情: 从 2016 年 6 月 17 日 UTC 上午开始,攻击者循环调用 splitDAO,以旁观者能在区块浏览器上实时看到的速度抽走以太币。攻击停止时,已有 3,641,694 枚 ETH 转入地址为 0x304a554a310c7e546dfe434669c62820b7d83490 的子 DAO。Vitalik Buterin 当天在以太坊博客发布紧急更新,公布资金被抽及拟议对策;攻击者随后不久停手,原合约中仍留有约三分之二的以太币。
- 技术架构创新:
- 重入是怎么发生的: splitDAO 函数在把内部代币余额清零之前,先把调用者应得的以太币发了出去。而向合约发送以太币会触发对方的 fallback 函数,于是攻击者的 fallback 直接再次调用 splitDAO——此时余额仍显示为原始的、未被扣减的数额。每一层嵌套调用都用同一批代币再提一次款。
- 两个漏洞的叠加: 单靠递归,受区块 gas 上限限制,每笔交易大约只能提二十次。攻击者还找到办法在代币被清零之前把它们转走,于是同一批代币可以在许多笔独立交易中反复使用,从两个地址各自重复了约 250 次。
- 28 天锁定争取到了时间: 由于子 DAO 在创建窗口内无法提款,被盗的以太币被原地冻结了约四周。以太坊之所以能够回应,恰恰是因为攻击者的资金被他们所利用的同一条规则锁住了。
- 直接影响: 以太币价格在一天内从约 20 美元跌到 13 美元左右。一个装着全部以太币 14% 的基金,被证明任何认真读过代码的人都能抽干。
- 长期意义:
- 重入成为智能合约的经典漏洞: 它是每一门 Solidity 课程讲的第一个漏洞,也是每一份审计清单上的第一项。
- 检查-生效-交互模式: 「先更新内部状态、再发起外部调用」这一防御纪律,加上显式的重入锁,都源自这次事件。
- 经验教训: 在合约里,一次外部调用不只是转移价值,更是移交控制权。任何在调用前尚未定稿的状态,都可能在调用期间被攻击。
- 后续发展: 重入漏洞此后十年仍在造成损失,包括 Uniswap V1 式资金池、Cream Finance,以及 2023 年 Curve 的 Vyper 编译器事件——足见这一类缺陷有多难根除。
3. 分叉:2016 年 7 月 20 日,区块 1,920,000
- 事件背景: 在子 DAO 的窗口关闭之前,以太坊开发者有四周时间。摆在面前的有三条路:什么都不做、审查攻击者的提款交易,或者改写受影响的余额。
- 事件详情: 最先提出的是软分叉,会让转移 DAO 资金的交易失效。在研究者证明它会给矿工打开拒绝服务攻击面之后,方案被放弃。社区随后转向硬分叉,执行一次「非常规状态变更」:在 2016 年 7 月 20 日挖出的区块 1,920,000 处,The DAO 及其子 DAO 的余额被移入一份简单的提款合约,原代币持有者可按每 100 个 DAO 兑 1 ETH 的比例赎回。一次不具约束力的按币投票显示多数支持——报道中的参与以太币约 85% 至 89% 赞成——但投票率只占总供应的一小部分。
- 技术架构创新:
- 分叉做了什么、没做什么: 没有任何交易被撤销,也没有任何区块被孤立。分叉是在指定区块高度直接修改状态中的账户余额,这也是它必须是硬分叉而非重组的原因。
- 起初没有重放保护: 分叉后的链最初与原链共享交易格式,交易可以在两条链上重放,直到交易所和钱包实现拆分手段之前,有用户因此损失资金。
- 直接影响: DAO 代币持有者被补偿完整。原 DAO 以太币中约 85% 最终通过提款合约被领回。
- 长期意义:
- 以太坊经典: 一部分矿工和用户坚持「账本不可被编辑」的原则,继续维护未分叉的链。它在数日内即被交易所上架,以 ETC 的形式存活至今,拥有自己的生态和对「代码即法律」立场的持续主张。
- 一个从未被重复的先例: 以太坊此后执行过许多次硬分叉,却再也没有为追回被盗资金做过第二次非常规状态变更——即便后来的损失规模远超 The DAO。
- 经验教训: 不可篡改的账本既是技术属性,也是一种社会承诺;而它只有在「遵守它的代价很高」时才真正被检验。
- 后续发展: 这次分叉第一次让以太坊的治理暴露在阳光下——核心开发者、矿工、交易所和代币持有者的混合体,没有正式流程。今天这个网络的治理方式,大体仍是如此。
4. 后果:证券法、审计业与一场永久的争论
- 事件背景: The DAO 同时在三个方向上产生了后果:法律、技术和哲学。
- 事件详情: SEC 2017 年 7 月的报告认定 DAO 代币属于投资合同、因而是证券,但未提起执法。审计行业在 2016 年几乎不存在,此后成长为任何管理大额价值的合约的标准前置条件。而以太坊与以太坊经典的分裂,则固化为一场关于「区块链规则能否为纠正某个结果而更改」的永久分歧。
- 技术架构创新:
- 形式化验证进入实践: 这次事件加速了相关工具的发展——用数学证明合约性质,而非仅靠经验测试。这类方法现已用于高价值协议。
- 直接影响: 大约在 2016 至 2018 年间,智能合约开发从一项研究活动变成一门带检查清单、审计与漏洞赏金的工程学科。
- 长期意义:
- 攻击者从未被起诉: 2022 年,记者 Laura Shin 发表调查,点名了一位特定人士,对方予以否认。此案从未提起指控,该指认也未在任何法院被确立。
- The DAO 的来世: 留在提款合约中未被领取的以太币最终被重新利用。在 2026 年前后的十周年之际,剩余余额——逾 75,000 枚 ETH、约合 1.3 亿美元——被投入一项以太坊安全捐赠基金,用于资助协议层面的安全工作。
- 经验教训: 一次攻击最昂贵的后果往往不是财务上的,而是制度上的:它留下的惯例、法律与分裂。
- 后续发展: 十年之后,DAO 管理着数十亿美元的金库,而其治理框架中的防御特性——时间锁、守护者、多阶段投票——几乎都可以追溯到 2016 年 6 月发生的事。
5. 关于 The DAO 攻击的常见误解
- 事件背景: 这个故事的几乎每一个环节都经常被说错,从「究竟是什么被攻破了」开始。
- 事件详情: 被攻破的不是以太坊。协议完全按规范运行,出问题的是部署在它之上的一份合约。攻击者也没有在代码可以分辨的技术意义上「偷」——每一次调用都是合法的,这恰恰是「要不要干预」如此难以决断的原因。硬分叉同样没有回滚区块链:没有区块被撤销,包括攻击者在内的每一笔 DAO 交易,至今在两条链上都还看得到。
- 技术架构创新:
- 以太坊经典才是原链: ETC 是分叉前账本的延续,ETH 是分叉出的那条链。命名习惯掩盖了这一点,因为规模更大的那条链保留了原名。
- 美元数字并不稳定: 被抽走的 364 万枚 ETH 常被折算为 5,000 万或 6,000 万美元,两个数字都出现在可靠来源中,原因是以太币价格在攻击期间与之后大幅下跌。可靠的是 ETH 的数量,美元价值取决于你选哪一刻。
- 直接影响: 把「什么失效了」说准确很重要,因为「以太坊被黑了」和「以太坊上的一个合约有 bug」,对平台安全性的含义完全不同。
- 长期意义:
- 一个不断被援引的判例: 此后每一次「回滚重大攻击」的提议——这样的提议有过好几次——都会被用 The DAO 分叉来论证,或作为先例,或作为警告。
- 双方最有力的论据是同一件事: 支持者看到的是一个年轻网络免于损失 14% 的供应;反对者看到的是一个在利益足够大时被证明可以编辑的账本。两种描述都属实。
- 经验教训: The DAO 并没有回答区块链是否应当不可篡改,它确立的是:这个问题是在公开场合、时间压力之下,由社会决定的。
- 后续发展: 原始的 DAO 合约、攻击者的子 DAO 和提款合约都还留在链上、可供查验,这让它成为行业史上被记录得最完整的一次智能合约失败。
常见问题
The DAO 攻击是怎么运作的?
splitDAO 函数在把调用者的内部代币余额清零之前,先支付了其应得的以太币。向合约发送以太币会触发其 fallback 函数,于是攻击者的合约在余额仍显示为全额时再次调用 splitDAO,在一笔交易里反复提款。
The DAO 一共被抽走多少 ETH?
3,641,694 枚 ETH,约占 The DAO 持仓的三分之一,被转入一个子 DAO。5,000 万和 6,000 万美元两个数字都出现在可靠来源中,因为以太币价格在攻击期间与之后大幅下跌;可靠的是 ETH 数量。
以太坊为什么要在攻击后硬分叉?
被盗以太币在子 DAO 中被锁约 28 天,给了社区行动时间。软分叉方案因会打开拒绝服务攻击面而被放弃后,开发者在 2016 年 7 月 20 日的区块 1,920,000 执行了一次非常规状态变更,把资金移入提款合约,DAO 代币持有者可按每 100 DAO 兑 1 ETH 赎回。
为什么会有以太坊经典?
一部分矿工和用户以「账本不可被编辑」为原则拒绝分叉,继续挖原链,那条链就是以太坊经典。技术上,ETC 是分叉前账本的延续,ETH 才是分叉出来的链——尽管规模更大的那条保留了原名。
硬分叉回滚了区块链吗?
没有。没有区块被孤立,也没有交易被撤销。分叉是在指定区块高度直接修改状态中的账户余额,这也是它必须是硬分叉的原因。包括攻击者在内的每一笔 DAO 交易,至今在两条链上都还看得到。
有人因 The DAO 攻击被起诉吗?
没有。2022 年有记者发表调查点名了一位特定人士,对方否认;此案从未提起指控,该指认也未在任何法院被确立。另外,SEC 在 2017 年 7 月认定 DAO 代币属于证券,但未提起执法。
参考资料
CRITICAL UPDATE Re: DAO VulnerabilityVitalik Buterin, Ethereum Foundation Blog (June 17, 2016)
(在新窗口打开)Hard Fork CompletedEthereum Foundation Blog (July 20, 2016)
(在新窗口打开)A Call for a Temporary Moratorium on The DAODino Mark, Vlad Zamfir and Emin Gun Sirer (May 27, 2016)
(在新窗口打开)Report of Investigation Pursuant to Section 21(a): The DAOU.S. Securities and Exchange Commission (July 25, 2017)
(在新窗口打开)