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

news/2024/11/10 1:39:21
新年前,我们最后来谈一谈以太坊安全性的特点。

不可能修改的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 合约

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官方交流群

clipboard.png


http://www.niftyadmin.cn/n/4334241.html

相关文章

表情包微信小程序

包括表情包、制作、贺卡、网络流行语。看看有什么地方可以改进。 转载于:https://juejin.im/post/5c556e02e51d457fd52eb316

pmc订单表格_好课共享 | 雷卫旭:精智工厂供应链营运Samp;OP交付计划物料控制PMC...

共享笔记2020 /12/ 29 星期二12月25日,由东莞市黄江镇人民镇府支持、黄江镇经济发展局主办的服务中小企业家课堂《精智工厂供应链营运S&OP交付计划物料控制PMC》主题讲座在格局商学东莞黄江分院开展。来自黄江镇上百家制造中小企业学员参与了此次服务中小企业家…

操作系统与程序运行以及进程简介 多线程上篇(一)

本系列将对Java多线程进行简单的介绍。分为上中下三个章节。 上篇对操作系统中关于进程、并发的相关概念以及问题进行了介绍; 中篇对Java多线程的基础进行介绍; 下篇将会对Java多线程编程提供的工具、模式进行介绍; Java多线程,首…

bgp通告四原则_BGP 路由反射器

路由反射器概述路由反射器的反射规则路由反射器环境下的防环Originator_ID属性Cluster_List属性Cluster_List属性对路由优选的影响路由反射器的配置路由反射器概述BGP在AS之间的路由防环依赖AS_PATH属性,但是AS_PATH属性只当路由在EBGP邻居之间传递时才会发生改变&a…

不会和容器一起启动_美团面试官:为什么不建议把数据库部署在Docker容器内?...

Hi,各位读者们,我是你们的鸭哥!由于最近公众号的改版,为了保证你们第一时间能看到鸭哥的文章,大家记得将公众号 加星标置顶 哦!来源:http://l.wz2.in/0AC近2年Docker非常的火热,各位…

不用缓存安装_Spring Boot 五种热部署方式,再也不用老重启了!

1、模板热部署在 Spring Boot 中,模板引擎的页面默认是开启缓存的,如果修改了页面的内容,则刷新页面是得不到修改后的页面的,因此我们可以在application.properties中关闭模版引擎的缓存,如下:Thymeleaf的配…

Netweaver和CloudFoundry的服务器日志

Netweaver 事务码SMICM,Goto->HTTP Plug-In->Server Logs: CloudFoundry 假设我部署本地应用到CloudFoundry之后,应用的状态变为CRASHED。然而从应用的控制台看不出太多有用的信息。 此时可以使用命令cf logs --recent来查看服务器端日志&#xff…

win10猎豹wifi间歇性掉线_无线WiFi间歇性掉线怎么办 无线WiFi间歇性掉线解决方法【详细介绍】...

正在看直播无线WiFi忽然掉线,游戏玩到决胜时刻网络问题聊个微信都间歇性的“网络连接不可用”,今天,小编将为大家讲解无线WiFi间歇性掉线如何搞定。一、避免信号干扰普通的家用路由器是在2.4G频段下工作的,而微波炉、电视机、冰箱…