如何保护您的智能合约:6 个 solidity 漏洞以及如何避免它们
fastdaily 区块链 2022-04-12 09:59:07 · 热度999



在之前的学习中,我们了解了以太坊可扩展性的未来。现在假设所有这些可扩展性问题现在都已解决,并且以太坊的智能合约可以正常工作。

这些用户是善意的,还是他们可能是干扰合约顺利运行的对手?

智能合约是“不可变的”。一旦部署它们,它们的代码就无法更改,因此无法修复任何已发现的错误。

在一个潜在的未来整个组织都由智能合约代码管理, 非常需要适当的安全。过去的黑客攻击,例如thedao 或今年的 parity hack (七月,十一月) 提高了开发者的意识,但这远远不够。

“这是黑客的迪士尼乐园”

在本文中,我们将介绍一些著名的安全陷阱及其缓解措施。

如何保护您的智能合约:6 个 solidity 漏洞以及如何避免它们-尊龙凯时ag旗舰厅

当一个数字增加超过其最大值时就是溢出。举个例子,solidity 最多可以处理 256 位数字(最多2²⁵⁶-1),因此增加 1 将导致 0。

0xffffffffffffffffffffffffffffffffffff
0x000000000000000000000000000000000001
----------------------------------------
= 0x000000000000000000000000000000000000

达到最大读数后,里程表或行程表从零重新启动,称为里程表翻转。

同样,在相反的情况下,当数字为无符号 unsigned 时,递减将使数字下溢,从而产生最大可能值。

0x0000000000000000000000000000000000000
- 0x000000000000000000000000000000000001
----------------------------------------
= 0xffffffffffffffffffffffffffffffffffff

尽管这两种情况都很危险,但下溢情况更有可能发生,例如在代币持有者拥有x个代币但试图花费 x 1的情况下。如果代码没有检查,攻击者最终可能会被允许超额花费并拥有一个最大化的余额。

缓解措施:一段时间以来,使用 openzeppelin 的safemath 库已成为标准做法。

2. 可见性和委托调用

如果在 7 月份你关注过类似问题的人,这个 bug 应该很熟悉,毕竟这是 parity 钱包黑客事件,让用户损失了大约 3000 万美元。

任何人都可以调用公共函数(通过合约内部的函数、继承合约的函数或外部用户)

外部函数只能被外部访问,这意味着它们不能被合约的其他函数调用。下面的要点没有编译,外部可见性cannotbecalled不允许它被合约的函数调用(但是它可以被另一个合约调用)

external 使用起来更便宜,因为它使用calldata操作码,而 public 需要将所有参数复制到内存。

private和internal更简单:private意味着该函数只能从合约内部调用,同时internal证明了更宽松的限制,允许从父合约继承的合约使用该函数。

也就是说,保留你的功能private ,除非internal 需要外部交互。

从solidity docs解释:

“delegatecall 与消息调用相同,区别在于,目标地址的代码在调用合约的上下文中执行msg.sender并且msg.value不会更改它们的值。

这意味着合约可以在运行时从不同的地址动态加载代码。存储、当前地址和余额仍然是调用合约,只是代码取自被调用地址。”

这个低级函数非常有用,它是实现库和模块化代码的支柱。然而,它打开了漏洞的大门。

在下面的示例中,攻击者可以调用合约 delegate 的公共函数pwn,并且由于调用是在上下文中的delegation,他们可以声明合约的所有权。

parity hack 涉及不安全的可见性修饰符和滥用delegate调用与 abritrary 数据的组合。易受攻击的合约的功能已实现delegatecall,另一个合约中可以修改所有权的功能被公开。这使得攻击者可以制作该msg.data字段来调用易受攻击的函数。

至于msg.data字段中包含的内容,那就是您要调用的函数的签名。sha3 (alias for keccak256)这里的签名是指函数原型散列的前 8 个字节。

在这种情况下:

web3.sha3('pwn()').slice(0, 10) --> 0xdd365b8b
如果函数接受参数,pwn(uint256 x):
web3.sha3('pwn(uint256)')。切片(0,10)-> 0x35f4581b

solidity 的call 函数在调用时value转发它收到的所有gas。在下面的代码段中,在实际减少发件人的余额之前,调用就已经进行了。这打开了一个漏洞,当 thedao hack 发生时,reddit评论中对此进行了很好的描述:

“简单来说,这就像银行出纳员在给你所有你要求的钱之前不会改变你的余额。“我可以提取 500 美元吗?等等,在那之前,我可以提取 500 美元吗?”

等等。设计的智能合约只在开始时检查你有没有 500 美元,就检查一次,还允许被打断。”

解决方法是在进行价值转移之前减少发件人的余额。对于使用过并行编程的人来说,另一种尊龙凯时ag旗舰厅的解决方案是使用mutexes

目前,使用msg.sender.transfer(_value) 是最佳实践。如果你真的需要使用send使用require(msg.sender.send(_value));

第 一 部分到此结束。第二部分将更新在老雅痞公众号上,我们将讨论一些鲜为人知的漏洞利用、应该添加到工作流程中的工具以及智能合约安全的未来。


文章推荐
1
2
fastdaily
0
0
网站地图