以太坊合约的安全性弱点,你都绕开了吗 III

新年前,咱们最后来谈一谈以太坊安全性的特色。

不可能修改的bug

当合约公开在区块链上以后,它就不能去修改了。相应的,合约中出现的任何 bug 也没有机会改正。若是但愿可以修改bug,合约编写者就须要在编写合约的时候预留一些用来修改或终止合约的代码。但预留修改后门这一方式具备争议,由于在以太坊的愿景中,智能合约一旦部署,其设定就应当是不可更改的。
正式由于 bug 不可修改,可能会致使一些很严重的攻击事件没有弥补的方法。DAO 攻击是惟一的例外。以太坊使用了一个硬分叉解决了这一问题。但这种作法没有获得整个社区的赞同,由于它违背了“代码即法则”这一准则。数组

调用栈大小限制

每次合约调用另外一个合约的时候,调用栈就会增长一个 frame. 上限是 1024 个。当这一上限达到的时候,下一次调用会触发一个异常。若是攻击者先将本身的调用栈离填满只差一个 frame,而后去调用受害者合约的函数,那么受害者函数执行中任何调用将会致使执行失败。若是受害者函数没有正确的处理执行成功与否,将可能致使意料以外的结果。在文章后续部分,咱们将以一个例子说明这一点。
为了解决这一问题,在一次以太坊升级中,规定了每次经过 call 或 delegatecall 调用合约函数时,只能为被调用函数分配最多 63/64 的剩余 gas. 而以太坊中每一个区块最多只能包含约 470 万的 gas。也就是说,若是调用者最初投入了数量为 a 的 gas, 在 10 层递归调用后,最内层的函数最多只有 (63/64)^10*a 的 gas. 所以,调用深度不可能超过 1024. 后面的攻击案例中,假设尚未这一修补方案。安全

时间约束

大量的应用使用时间约束来决定某些行为何时候被容许。好比在一个 ERC 20 合约中,从某个时刻开始,容许用户使用 ether 购买一个 token.
在智能合约的执行过程当中,当前时间取自给定交易所在区块的区块时间戳。因此,一个区块中的全部交易在执行时使用的是相同的时间戳。这一设定保证了智能合约在每一个矿工那里的执行结果是一致的。
但这个设定也可能致使一些攻击,由于矿工在选择时间戳的时候有必定的自主权,这可能为一些攻击埋下了后门。微信

GovernMental 合约的攻击

GovernMental 是一个“庞氏骗局游戏”型合约。严格来讲,其实不能叫骗啦,由于庞氏骗局的规则被公开地写在合约里。在这个合约中,每一个人经过向合约中转一笔钱来加入这个庞氏骗局游戏。合约经过两个数组记录参与者的地址和每一个参与者转入的钱的数量。若是最后一我的加入后 12 小时后都没有下一我的加入,那么最后一我的就能够得到所有的收益。(这个设定是否是有点像著名的 Fomo3D,值得注意的是,Fomo3D 的出现晚于这篇论文呦。)
下面是一个简化版的 GovernMental 合约ide

clipboard.png

在这个合约中,参与者能够经过 invest() 函数来投入 ether 并加入这个游戏。合约维护一个名为 jackpot的变量,表示若是后续没有人加入,赢家将拿走多少 ether. 新来的参与者必须投入多于 jackpot 一半的 ether, 同时,新来的参与者投入的 ether 中,会有一半被加入 jackpot. 若是连续一分钟没有人新来的参与者,最后一我的得到 jackpot 中的 ether,同时合约拥有者拿走剩下的钱(留下 1 个 ether 做为下一轮的启动资金)。须要注意的是,这里并无检查最后分钱的时候,经过 send() 函数进行的转帐是否成功。
这个简化版的合约有几个点可供被攻击。函数

攻击一

这个攻击来自合约拥有者自身,目的是让原本的游戏赢家没法拿到钱。合约拥有者利用 send() 函数的异常处理和调用栈大小限制进行攻击。
攻击的方式是,经过预先进行大量的递归调用,致使执行 resetInvestment() 时,调用栈达到了大小上限,没法再执行给游戏赢家和合约拥有者的 send() 函数。合约拥有者和游戏赢家都拿不到钱,钱依然留在合约中,但以后重置合约状态的代码会照常执行。只要再进行一轮正常的游戏,合约拥有者就能够将本该属于上一轮游戏赢家的钱收入囊中。性能

攻击二

这一攻击方式来自矿工。矿工能够经过拒绝打包其余人与 GovernMental 合约的交易,来使本身但愿的人成为合约游戏的赢家。更多地,进行攻击的矿工在打包区块时能够任意决定交易顺序,来影响这个区块事后谁是 lastInvestor.
以前也提到过,每个新参与者须要投入的 ether 数量不能低于合约中 jackpot 中 ether 数量的一半。而一我的在发起交易的时候看到的 jackpot 数值,与它的交易被执行时 jackpot 的数值多是不同的。这就致使这我的可能发起交易时觉得本身投入的 ether 数量是符合要求的。可是执行时,因为 jackpot 数值的改变,变成了一笔无效交易。这就是上篇文章中提过的不可预测状态问题。
另外,矿工拥有决定区块时间戳的权利。而合约在执行时,断定 resetInvestment 是否能够执行,就是读取矿工决定的区块时间戳。经过影响区块时间戳,也能够影响游戏结果。学习

结语

经过这几期对参考文献 [1] 的学习,咱们看到了一些以太坊 Solidity 合约中设计的弱点。虽然这些弱点称不上是漏洞,可是若是在编写合约时,对这些点不了解,没有充分考虑,就可能写出有安全问题的合约出来。
参考文献:
[1] Atzei, Nicola, Massimo Bartoletti, and Tiziana Cimoli. "A survey of attacks on ethereum smart contracts (sok)." Principles of Security and Trust. Springer, Berlin, Heidelberg, 2017. 164-186.区块链

--
Conflux 是致力于打造下一代高性能的 DAPP 公链平台
欢迎关注咱们的微信公众号:Conflux中文社区(Conflux-Chain)
添加微信群管理员 Confluxgroup 回复“加群”加入 Conflux官方交流群spa

clipboard.png

相关文章
相关标签/搜索