当前位置:网站首页>智能合约安全——随机数
智能合约安全——随机数
2022-08-05 17:55:00 【fingernft】
本次我们将带大家了解智能合约中一个经常被用到的东西——随机数。智能合约的开发中常常会用到随机数,例如 Lottery 和现在流行的 NFT 数字藏品的属性等都需要用到随机数。目前来说常见的随机数获取有两种:使用区块变量生成随机数,使用预言机来生成随机数。下面我们了解一下这两者的特点:
1)使用区块变量生成随机数
我们先了解一下常见的区块变量有哪些:block.basefee(uint):当前区块的基本费用block.chainid(uint):当前链 idblock.coinbase():当前区块矿工地址 address payableblock.difficulty(uint):当前区块难度block.gaslimit(uint):当前区块 gaslimitblock.number(uint):当前区块号block.timestamp(uint):自 Unix 纪元以来的当前区块时间戳(以秒为单位)blockhash(uint blockNumber) returns (bytes32):给定区块的哈希,仅适用于 256 个最近的区块
其中 block.difficulty, blockhash, block.number 和 block.timestamp 这四个是用得比较多的。由区块数据生成的随机数可能会限制普通用户预测随机数的可能性,但是并不能限制矿工作恶,矿工可以决定一个区块是否被广播,他们挖出了一个区块不是一定要广播出去也可以直接扔掉,这个就叫矿工的选择性打包。他们可以持续尝试生成随机数,直至得到想要的结果再广播出去。当然,矿工会这样做的前提是有足够的的利益诱惑,例如可以获得一个很大的奖励池中的奖励,因此使用区块变量获取随机数的方法更适合于一些随机数不属于核心业务的应用。
2)使用预言机生成随机数
预言机是专门为生成随机数种子而搭建的链上或者链下的服务。除了使用第三方服务,也可以由 DApp 开发商自己搭建一个链下服务提供随机数,这种在链上获取链下数据的场景通常是通过链上预言机的方式来实现。
当然这种方法也会有一些安全风险,例如依赖第三方给出的随机数种子的话同样会存在第三方作弊或者受贿的情形,即使是自己搭建的随机数服务也可能因为故障等原因无法使用,项目方也有可能操控随机数对 DApp 的运行和用户造成重大的损失。因此使用链下服务获取随机数的方法依赖于是否有一个可信又稳定的第三方服务,如果有,那么这个方法相较于使用区块链变量生成随机数的方法,随机数的不可预测性会更强一些。
接下来我们还是用合约代码来给大家演示弱随机数可能带来的危害。
漏洞示例

漏洞分析
首先我们先来了解一下代码中的两个函数,abi.encodePacked 和 keccak256:
abi.encodePacked 对参数进行编码,solidity 提供两种编码方法 encode 和 encodePacked,前者对每一个参数进行 32 字节补齐,后者不进行补齐而是直接将待编码参数连接起来。
keccak256 哈希算法,可以将任意长度的输入压缩成 64 位的 16 进制的数,且哈希碰撞的概率近乎为 0。
接下来我们来看合约代码,这个合约是一个猜数字赢以太的游戏,我们可以看到,部署者使用上个区块的区块哈希和区块时间作为随机数种子生成随机数,我们只需要模拟他的随机数生成方法就可以得到奖励。下面我们来看攻击合约:
攻击合约

下面我们先来分析攻击流程:
攻击者调用Attack.attack()函数,它模拟了 GuessTheRandomNumber 合约中随机数的生成方式生成随机数后调用 guessTheRandomNumber.guess() 并将生成的随机数传入,由于从 Attack.attack() 生成随机数到调用 guessTheRandomNumber.guess() 都是在同一区块中完成的,且在同一区块中 block.number 和 block.timestamp 这两个参数是不变的,所以,Attack.attack() 和 guessTheRandomNumber.guess() 这两个函数生成的随机数的结果是相同的,从而攻击者可以顺利通过 if(_guess == answer) 判断得到奖励。
修复建议
如果随机数属于非核心业务的话可以使用未来区块哈希来生成随机数也就是将猜数和领奖分开做异步处理。针对这次的漏洞合约写一个优化版本,大家可以看下:

添加了deadline 参数将 guess 和 claim 做异步处理后,在部署合约后的 72 小时内可以调用 guess() 猜随机数,在 72 小时后 guess() 关闭 claim() 开启,玩家可以通过 claim() 来验证自己是否猜中。当然,这个修复合约并不是完美的解决方案,正如前置知识中提到的,如果矿工来玩的话他可以在打包的时候知道自己是否猜中,如果猜中打包上链,如果没有猜中放弃打包(相信没有任何一个矿工愿意为了得到一个以太而付出这么大的代价)。所以最优的解决办法还是接入知名预言机来获取随机数。
如果想了解更多的智能合约和区块链知识,欢迎到区块链交流社区CHAINPIP社区,一起交流学习~社区地址:https://www.chainpip.com/
边栏推荐
- AIRIOT Q&A Issue 7 | How to quickly improve the delivery speed of IoT projects?
- [Today in History] August 5: WeChat 5.0 was released; Baidu was listed; LinkedIn founder was born
- 工作中必会的57个Excel小技巧
- ICML 2022 | 图神经网络的局部增强
- 微服务Client模块
- img幽灵空白的解决方法
- 基于ABP和Magicodes实现Excel导出操作
- Ventoy系统启动盘制作
- 学 Go,最常用的技能是什么?打日志
- EN 12259-3喷水灭火系统干式报警阀组件—CE认证
猜你喜欢
Moyck 的 App 库

新一代主机安全4大核心技术和15大应用场景

【OAuth2】十五、客户端认证流程-自定义授权页面和客户端认证

如何成为一名合格的 DBA?看看“老油条”们怎么说

How to activate the latest version of IntelliJ IDEA 2022.2

A new generation of host security four big core technologies and 15 application scenario

Meet Alluxio, the "middleman" in MRS

HJ41 称砝码 HJ41 称砝码

营销之王完美日记卖不动了

实操演示:每日站会怎么开才能更高效?
随机推荐
DRM架构下如何点亮一块屏
如何成为一名合格的 DBA?看看“老油条”们怎么说
脑间同步:道阻且长
【623. 在二叉树中增加一行】
【数据挖掘】顺丰公司数据挖掘笔试题
文末送书 | CCF优秀博士论文丛书:搜索引擎中的实体推荐关键技术研究
招商证券股票开户流程是怎么样的?开户安全吗?
超级玛丽问号盒子3d旋转js特效
INPUT
一套多用表单小部件代码下载
FinClip | 2022 年 7 月产品大事记
【已解决】pnpm(Run “pnpm setup“ to create it automatically, or set the global-bin-dir setting, or the PNP
puzzle(005)单元拼接问题
How WPF+SkiaSharp implements self-drawn shooting game
科研实习 | 北京大学万小军老师课题组招收NLP方向实习生和访问学生
SAP ABAP EXCEL 导入
AIRIOT Q&A Issue 7 | How to quickly improve the delivery speed of IoT projects?
rk3399 休眠唤醒standby调试指南
C语言的文件操作
认识一下MRS里的“中间人”Alluxio