又一个重入攻击 - 是什么阻止我们成为更好的智能合约开发者?

本文探讨了Web3中智能合约重入攻击等常见安全问题依然存在的原因,提出了开发者应具备安全意识,将安全验证纳入开发流程,并鼓励开发者通过实验和犯错来加深对Solidity语言的理解,从而提升智能合约的安全性。文章强调了在学习和开发智能合约时,实验和安全性的重要性。

自从震撼整个 web3 世界的臭名昭著的 DAO 黑客事件以来,已经过去了 6 年 3 个月零 25 天

那次事件中,由于智能合约中的一个漏洞,我们目睹了超过 350 万以太币被盗。

这次黑客攻击向我们介绍了智能合约中可能出现的最危险的攻击之一,即 重入攻击

从那时起,人们进行了大量的改进和尝试,以降低在智能合约中引入此类攻击向量的风险。

自动化测试工具开始包含关于重入漏洞的警告,智能合约审计员对处理外部调用的代码变得特别谨慎,并且创建了大量博客以及视频内容(并且仍在制作中)来解释重入攻击。

然而,如果你观察过去几年的漏洞利用,除了所有其他新的攻击向量之外,重入漏洞仍然是一个主要问题,并且可以被视为许多智能合约漏洞背后的一个重要错误。

让我与你分享一下所有由于重入而导致的智能合约攻击的概况,请查看下面的列表

事实上,我读到的最新的重入漏洞利用就在几周前,当时Stader 的 NearX 智能合约被利用,利用的是完全相同的众所周知的重入漏洞,损失了 830,000 美元。

可怕,不是吗? 😰

好吧,这不仅仅是关于智能合约中的重入漏洞,这个博客也不会解释重入漏洞(不再重复)。

重入攻击只是智能合约开发社区非常清楚的众多众所周知的攻击之一,但即使在今天,我们仍然在智能合约中发现此类错误的痕迹,这导致了极其严重的漏洞利用。


现在的问题是——为什么?

尽管在 solidity 中有大量关于此类常见错误和攻击向量的工具、库和教育内容,为什么我们仍然一次又一次地看到此类众所周知的攻击?

毫无疑问,这是一个宽泛或开放式的问题,可能有多种说法或答案。

然而,在参与了多次智能合约安全审计、与相当多的智能合约开发人员互动以及成为一些非常活跃的智能合约开发者社区的一员之后,我发现了背后两个极其简单但必不可少的原因。

最重要的是,这些原因围绕着我们如何处理智能合约开发和学习 Solidity 的基本原理,尤其是在初始阶段。

1. “安全不是我的工作”的心态

毫无疑问,web3 领域的大多数开发人员都认为合约开发和智能合约安全是两件不同的事情,这在某种程度上是正确的。

然而,完全否认这两件事之间的任何关联可能是一个错误。

这背后的理由是,在最核心的层面,智能合约开发过程大致包括 3 个最重要的步骤:

  • 设计与开发
  • 优化
  • 合约的安全验证

虽然我们非常清楚前两个步骤,但我们最常忘记,或者更糟糕的是,根本不认为安全验证是合约开发过程的一部分。

这令人担忧,因为即使我们考虑到关于智能合约的一个基本事实,即它们在链上部署后的不可变性质,我们也可以清楚地看到将安全检查和验证作为智能合约开发过程中的强制步骤的重要性。

即使在部署后几秒钟发现了一个重大错误,你也无法更改合约中的一行代码,这个事实本身就令人望而生畏。

好吧,以防你认为你总是可以升级你的智能合约,或者可升级的合约非常安全,让我立即阻止你。🛑

阅读关于 Wormhole 代理漏洞 并再想一想。

可升级的合约也可能有错误。🪲

你应该怎么做?

用非常简单的话来说,将安全检查和验证视为你开发的任何智能合约的必要组成部分,并且至少学习智能合约安全的基础知识,如果你还没有这样做的话。

一旦你考虑到这一点,你就不能再仅仅依赖于为你的智能合约编写测试用例。

毫无疑问,测试脚本很有帮助,但是,它们更倾向于确保合约功能按预期执行,而合约的安全性远不止于此。

即使作为一名智能合约开发人员,你也绝对应该擅长使用以下(实际上不止 1 个)安全工具中的至少一个来验证你的合约的安全性:

  • 静态分析工具,例如 SlitherMythrilMythx 这些工具可以有效地帮助你识别合约中可能存在的任何众所周知的智能合约错误。
  • 模糊测试工具,例如 EchidnaHarvey 通过将随机和意外的数据扔到你的合约中,帮助识别潜在的漏洞利用场景或合约执行失败。
  • Scribble,这是 ConsenSys 提供的一个了不起的运行时验证工具,允许你使用关键属性注释 solidity 智能合约。
  • 在审计复杂且庞大的智能合约时,你最需要的是可视化工具,而这正是 Surya 发挥作用的地方。

它提供了合约结构所有关键细节的极其简化的版本,包括调用图、继承图等。

  • VS Code visual auditor 扩展是一个非常有用的工具,它提供面向安全的语法以及语义高亮显示和一些其他工具,使合约的安全开发更容易。

我最喜欢的是 → Slither, Surya, VS Code visual auditor, and Echindna。😎

你为什么要这样做(如果你可以获得合约审计)?

首先,没有人会比你(和你的团队)更关心你的智能合约的安全性。对你的代码的安全性负责的第一人应该是

其次,智能合约审计行业一直(并且仍然是)处于“高需求和低供应的优秀安全审计员”阶段

这基本上意味着只有少数经验丰富的审计员,并且仅仅依靠他们中的少数人对于 web3 世界呈指数级增长来说,并不是真正可扩展的。

此外,有大量的项目在等待他们的合约被审计,这就是为什么,当轮到你时,你需要准备好正确的合约集、足够的测试用例、覆盖率报告,最重要的是,你可能想与你的安全审计员讨论的关键点。

但是,如果你自己不了解智能合约安全的基础知识,你将无法与智能合约安全专家进行任何有效的讨论。

在你的智能合约开发过程中包含安全验证步骤,可以让你借助静态分析工具预先过滤掉所有众所周知的错误。

这使得安全审计员可以专门专注于合约的更重要的潜在威胁,而不是识别和报告那些可以很容易地通过上述工具找到的威胁。

因此,在审计之前执行你自己的安全检查不仅缩短了漫长的审计时间,而且有助于从整个过程中获得充分且更好的结果。

Secureum 社区 将这个概念精彩地定义为 CARE(全面审计准备评估,旨在在审计之前准备好你的合约,以确保安全审计的结果相对更好且更有效。

重要的是要注意,将安全性作为智能合约开发过程的一部分不能替代对你的合约的审计,而是为充分的安全审计做准备。

2. 避免错误和 Solidity 实验(以及从中获得的经验)

好的,虽然第一点是针对已经熟悉 solidity(和智能合约安全基础知识)的开发人员,但这一部分更倾向于那些刚开始学习 solidity 或处于智能合约开发早期阶段的人。

这里有一个快速提示给你:

在学习和开发简单的 solidity 智能合约的同时,不要害怕在学习 solidity 时进行实验和犯错。

自诞生以来,Solidity 或一般的智能合约开发对于许多开发人员来说,在早期阶段一直非常有趣但同时也令人望而生畏和困难,原因很明显:

  • 智能合约的不可变特性以及在链上部署之前一次性完成几乎所有事情的想法。
  • 智能合约的开源特性以及每一行代码都可被任何人访问/读取的事实。
  • 在智能合约中编程和存储资金以及随之而来的安全风险的整个概念。
  • Solidity 仍然处于非常初级的阶段,并且难以跟上快速变化/发展的语言。

现在,与开发智能合约时犯错相关的担忧和风险不容忽视。但是,这些对有效学习智能合约的旅程产生了不利影响。

由于风险如此之大,开发人员实验Solidity或自己犯错变得更加困难。

不要重新发明轮子或尝试新事物,以避免在合约中引入新错误”的流行观念阻止了开发人员探索 solidity 的不同概念,从而限制了他们在整个智能合约开发中的潜力。

事实上,现在认为简单地 fork 一个已经存在的经过审计的合约而不是从头开始编写一个合约要安全得多。虽然这确实最大限度地降低了合约在生产中出现错误的风险,但它确实阻止了开发人员处理在开发相同合约时可能(并且应该)经历的所有复杂情况。 因此,它使我们很少深入研究 solidity 概念。

虽然简单地学习区块链开发课程或消费关于智能合约的在线内容可能有助于你开始学习任何特定主题,但它不会让你深入研究并学习基础知识。除非你亲自动手。

最重要的是,不实验 Solidity 智能合约也使我们无法了解合约可能具有的各种安全漏洞以及破坏合约的多种方式。

例如,回到重入示例:

每个智能合约开发人员可能都听说过、阅读过或讨论过重入攻击向量,但我们中有多少人实际上继续尝试在一些虚拟合约上进行实验,只是为了了解幕后发生了什么?

这正是基于智能合约安全性的战争游戏或 CTF(如 Ethernaut Damn Vulnerable Defi)在学习智能合约开发和安全性方面也发挥着如此重要的作用。 它们允许你直接与合约交互,犯错并最终找出漏洞。

现在,肯定有一些智能合约开发人员对 Solidity 和智能合约进行了大量实验,因此正在成为行业中最好的(_查看 Underhand Solidity Contest winners 或他们的 Challange Submissions , 例如)。

2022 年 Underhanded Solidity Contest 的获胜者

但是,正如我前面提到的,为了让 web3 世界扩展其边界并以最安全的措施进行扩展,我们不能仅仅依靠该领域少数的专家。

相反,每个智能合约开发人员都应该渴望学到更多,并通过不仅学习基础知识,而且进行实验、犯错、从中学习,然后与社区分享这些经验来深入研究。

因为,与一般的生活非常相似,软件开发中最好的学习也来自错误。

错误和学习经验的重要性

每个智能合约开发人员至少应该经历一次的 错误或学习经验

如果你只是刚开始使用 Solidity,那么在学习时你可以(而且应该)做很多错误/实验。

从我的脑海中删除一些。

Solidity 101 错误/学习:

  1. 使用 memory 关键字而不是 storage,然后意识到你从未真正将关键合约状态永久存储在合约上。
  2. 依靠区块时间戳进行随机计算,并意识到矿工如何操纵它们,因此这是一种不好的做法。更多细节在此处 here .
  3. 仅使用私有可见性修饰符将秘密信息存储在智能合约状态变量上,结果却发现智能合约上没有任何内容是私有的。

每个人都可以看到每个状态变量值。_在此处 SWC-136 中阅读更多相关信息_

  1. 你将始终相信没有 payable 函数(或 payable 回退函数)的合约永远不会收到任何以太币,除非你学习了 selfdestruct 如何强制使用 ETH 为此类合约提供资金。
  2. 无法在函数中提供所需的 输入验证 并且意识到这会导致不需要的场景,因为任何无效参数都可以在没有适当验证的情况下传递。(SWC-123

Gas 优化和安全错误/学习:

6. 编写昂贵的 for 循环,结果却发现这可能导致 区块 gas 限制 问题并导致整个交易失败

7. 违反 检查效果交互模式 并意识到这可能导致经典的重入攻击。

8. 在具有不同存储布局的两个合约之间使用 delegate 调用,并意识到如果 delegate 调用要工作,为什么存储布局必须完全相似。

确保参与 delegatecall() 的两个合约之间的存储布局完全相同非常重要。 否则,这会导致存储冲突。 在此处阅读有关存储冲突的更多信息here

9. 为合约的重要函数赋予不足的访问控制,并意识到这可能导致任何不良行为者未经批准执行交易。SWC-105 非常充分地涵盖了此主题。

10. 尝试使用 transfer 函数将以太币从一个合约发送到另一个合约,结果却发现它始终只发送硬编码的 2100 gas。 这将帮助你了解 .call.value(…)(“ ”) 函数的重要性,该函数允许调整与交易一起发送的 gas。 在此处阅读更多关于为什么 .call() 可能比 transfer() 更好 .

11. 意识到删除 struct 中或一般的映射值是多么棘手,并学习正确的做法。

12. 尝试使用 Uniswap 交换 Token AToken B,并且容易受到夹层攻击。 这可能会帮助你意识到交易顺序依赖性、MEV 和 以太坊的黑暗森林 的阴暗面。

怀特先生正在试验 Solidity

虽然这些只是一些例子,但在智能合约开发中还有更多有趣的主题,从基本的 solidity 到 EVM Opcodes 的高级深入研究,人们可以学习和实验。

总结 😊

Web3 在很短的时间内取得了长足的进步,但是,智能合约的安全性仍然是一个主要问题。

上面讨论的两个想法不会一次性地让一切都变得阳光明媚。 毫无疑问,我们需要做更多的事情才能使 Web3 成为一个更安全的地方。

然而,想象一下,整整一代的开发人员在学习或开发智能合约时都牢记上述两个想法,优先学习安全基础知识,进行 Solidity 实验,从他们的错误中学习,然后与社区分享这些经验。

与我们现在拥有的相比,这将慢慢地但肯定地将我们引向一个更安全和更可靠的 web3 世界。

你所需要的只是坚持不懈的承诺,从错误和实验中学习更多的意愿,以及渴望成为你已经拥有的更好的智能合约开发人员。

如果我可以给你留下两句话 👇

学习智能合约 时不要忘记 实验

开发智能合约 时不要忘记 安全

  • 原文链接: decipherclub.com/another...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
decipherclub
decipherclub
江湖只有他的大名,没有他的介绍。