智能合约代码通常无法修改来修复安全漏洞,因此从智能合约中被盗窃的资产是无法收回的,且被盗资产极难追踪。 由于智能合约问题而被盗取或丢失的价值总额很容易超过 10 亿美元。 仅仅在项目结束时对您的智能合约进行审计已经不足以成为项目的唯一安全考虑。 安全性来源于适当的设计和开发过程,所以在您编写第一行智能合约代码之前,安全性就应该被考虑。 重入攻击重入攻击时在编写智能合约代码时应该考虑的最大且最重要的安全问题。 虽然以太坊虚拟机不能同时运行多个合约,一个合约可以调用另一个合约来暂停一个合约的执行和内存状态,直到被重新调用。 其他攻击除了上面的重入攻击,智能合约还会收到许多其他类型的攻击需要注意,例如:·溢出攻击·自毁攻击·delegatecall数据篡改·随机数问题安全工具虽然了解以太坊安全基础知识和聘请专业审计公司审查您的代码是无可替代的 ,但在合约编写的过程中学会使用安全工具,能帮助你更有效率的发现和改正代码中出现的错误和漏洞。
举个例子: 合约A 图片 合约B 图片 当合约B调用testDelegatecall()函数时,合约B的地址c的值会变为合约A的地址,而地址a则是不变。 因为合约A的函数test()改变的是插槽slot1的值,同样的在合约B中运行时,改变的也是插槽slot1的值,即地址c的值。 目标合约 图片 漏洞分析 我们可以看到有两个合约,Lib 合约中只有一个 pwn 函数用来修改合约的 owner,在 HackMe 合约中存在 fallback 函数,fallback 函数的内容是使用 Lib 合约中恰好有名为 pwn 的函数,于是便在HackMe 合约中运行了pwn函数; 4.pwn函数修改了插槽slot0位置(即HackMe 合约的拥有者)的值为msg.sender(即攻击者),最终导致了 在使用 delegatecall 时应注意被调用合约的地址不能是可控的; 2. 在较为复杂的合约环境下需要注意变量的声明顺序以及存储位置。
众所周知,以太坊的转账不仅可以在钱包地址之间进行,合约与钱包地址之间、合约与合约之间也可以,而合约在接收到转账的时候会触发 fallback 函数执行相应的逻辑,这是一种隐藏的外部调用。 攻击者就会利用这一点,在合约的fallback 函数中写入恶意逻辑重新进入到被攻击的合约内部,让被攻击的合约执行非预期的外部调用,从而到达获取不正当利益的目的。 函数一直提币从而将合约账户清空。 攻击合约下面我们看看攻击者编写的攻击合约中的攻击手法是否与我们的漏洞分析相同:图片我们看到 EtherStore 合约是一个充提合约,我们可以在其中充值和提现。 记住所有涉及到外部合约调用的代码位置都是不安全的。那么智能合约中的重入攻击就讲解完了,如果想了解更多的区块链知识,或是有什么疑问,可以到区块链交流社区CHAINPIP来,一起学习和交流。
selfdestruct函数(自毁函数)由以太坊智能合约提供,用于销毁区块链上的合约系统。当合约执行自毁操作时,合约账户上剩余的以太币会发送给指定的目标,然后其存储和代码从状态中被移除。 selfdestruct函数虽然能在紧急情况下帮助开发人员删除智能合约并将合约内的余额转移到指定的地址,但这一特性也被不法分子利用,使它成为了攻击手段。 玩家每次玩游戏时都会调用 EtherGame.deposit 函数向合约中先打入一个ETH,随后函数会检查合约中的余额(balance)是否小于等于 7 ,只有合约中的余额小于等于 7 时才能继续否则将回滚 合约中的余额(balance)是通过 address(this).balance 取到的,这就意味着我们只要有办法在产生 winner 之前改变 EtherGame 合约中的余额让他等于 7 就会使该合约瘫痪 攻击合约 图片 攻击者调用攻击函数attack()销毁合约并将合约中的余额强制转账到“幸运7”的游戏合约地址,制造出游戏合约查询余额address(this).balance大于7的情况,导致函数回退,
图片如果一个合约有溢出漏洞的话会导致计算的实际结果和预期的结果产生非常大的差异,这样轻则会影响合约的正常逻辑,重则会导致合约中的资金丢失。 所以当我们看到 0.8 版本以下的合约时,就要注意这个合约可能出现溢出问题。 首先我们发现这个合约中的 increaseLockTime 函数和 deposit 函数具有运算功能,并且合约支持的版本是:0.7.6 向上兼容,所以这个合约在算数溢出时是不会报错的,那么我们就可以判断这个合约是可能存在溢出漏洞的 攻击合约下面我们来看看攻击合约:图片这里我们将使用 Attack 攻击合约先存入以太后利用合约的溢出漏洞在存储未到期的情况下提取我们在刚刚 TimeLock 合约中存入并锁定的以太:1. 首先部署 TimeLock 合约;2. 再部署 Attack 合约并在构造函数中传入 TimeLock 合约的地址;3.
目标合约漏洞分析这次的攻击目标依然是获得 HackMe 合约中的 owner 权限,我们可以看到两个合约中除了 HackMe 合约中的构造函数可以修改合约的 owner 其他地方并没有修改 owner 的函数,但是却可以修改位置slot0的值,而HackMe 合约中插槽slot0表示的便是Lib的地址,那么我们就先修改Lib的地址为我们的地址,再次调用HackMe 合约时就会运行我们合约中的逻辑,那么想改哪个位置插槽的值不就都由我们控制了吗 攻击合约下面是我们本次的攻击合约:接下来我们来看看攻击的整个逻辑:1. 函数时也将改变自己在 slot0 位置存储的变量的值,也就是将 lib 参数(这里存储的是 Lib 合约的地址)改为我们传入的 Attack 合约的地址。 修复建议我们在合约的开发中使用delegatecall要时刻注意其被调用的合约地址要始终在我们设计的逻辑内运行,不能让其有可能超出我们设计时的适用范围,一旦出现了超出我们预期设计的情况,那么合约就有可能被不法之徒利用
漏洞示例 示例合约如下所示: pragma solidity ^0.4.25; contract TypoOneCommand { uint numberOne = 2; function alwaysOne() public returns(uint a){ return numberOne =+ 1; } } 编译并部署合约之后调用alwaysOne来进行简易测试 防御措施 1、所有的数值运算操作全部采用SafeMath来实现 2、使用最新的编译器,最新版本编译器会自动检测是否存在类似的安全问题 ?
本次我们将带大家了解智能合约中一个经常被用到的东西——随机数。智能合约的开发中常常会用到随机数,例如 Lottery 和现在流行的 NFT 数字藏品的属性等都需要用到随机数。 当然这种方法也会有一些安全风险,例如依赖第三方给出的随机数种子的话同样会存在第三方作弊或者受贿的情形,即使是自己搭建的随机数服务也可能因为故障等原因无法使用,项目方也有可能操控随机数对 DApp 的运行和用户造成重大的损失 接下来我们还是用合约代码来给大家演示弱随机数可能带来的危害。 接下来我们来看合约代码,这个合约是一个猜数字赢以太的游戏,我们可以看到,部署者使用上个区块的区块哈希和区块时间作为随机数种子生成随机数,我们只需要模拟他的随机数生成方法就可以得到奖励。 下面我们来看攻击合约:攻击合约图片下面我们先来分析攻击流程:攻击者调用Attack.attack()函数,它模拟了 GuessTheRandomNumber 合约中随机数的生成方式生成随机数后调用 guessTheRandomNumber.guess
,导致资产损失甚至系统崩溃,因此对智能合约进行安全审计是至关重要的,本文将概述智能合约安全审计技术的相关知识为读者带来更深入的了解 智能合约 智能合约是一种基于区块链技术的自动化合约,它可以在没有第三方干预的情况下自动执行合约条款并将结果记录在区块链上 编码设计 DASP Top 10归纳了智能合约常见的安全漏洞,智能合约开发人员在开发合约之前可以先研习智能合约安全漏洞以规避在开发合约时出现安全漏洞,合约审计人员可根据DASP Top 10对智能合约已有安全漏洞进行快速审计检查 安全性:智能合约需要保证安全性,选择具有良好安全保障的语言可以提高安全性 生态支持:选择有完善的生态支持的语言可以提高开发效率和稳定性 ...... 场景覆盖面充分以及合约代码的覆盖率 安全审计 智能合约在正式上线之前建议先寻找可靠的、可信任的第三方区块链智能合约安全审计公司对合约的安全性进行安全审计评估,在初次审计完成后需要对合约中存在的安全漏洞进行修复调整 ,同时在修复后还需要请安全审计公司再次进行安全审计来检查漏洞修复是否有效可行,同时也建议项目方在进行安全审计的时候可以邀请2-3家安全审计公司进行审计来实现对合约安全的多重安全保障 文末小结 智能合约安全审计是区块链应用开发过程中不可或缺的一环
其中,Fabric联盟链平台智能合约具有很好的代表性,本文主要分析其智能合约安全性,其他联盟链平台合约亦如此,除了代码语言本身的问题,也存在系统机制安全,运行时安全,业务逻辑安全等问题。 语言特性问题 不管使用什么语言对智能合约进行编程,都存在其对应的语言以及相关合约标准的安全性问题。Fabric 智能合约是以通用编程语言为基础,指定对应的智能合约模块。 •访问外部资源 合约访问外部资源时,如第三方库,这些第三方库代码本身可能存在一些安全隐患。引入第三方库代码可能会暴露合约未预期的安全隐患,影响链码业务逻辑。 •外部合约调用引入安全隐患 在某些业务场景中,智能合约代码可能引入其他智能合约,这些未经安全检查的合约代码可能存在一些未预期的安全隐患,进而影响链码业务本身的逻辑。 总结 联盟链的发展目前还处于项目落地初期阶段,对于联盟链平台上的智能合约开发,项目方应该强化对智能合约开发者的安全培训,简化智能合约的设计,做到功能与安全的平衡,严格执行智能合约代码安全审计(自评/项目组
然而,安全不是一个检查清单,安全是一个过程,不仅在编写代码时,而且在项目和架构的设计时就得首先考虑,安全应该成为你心态的一部分。 开发和协作过程中的安全问题 安全问题产生的很大一部分原因是不言而喻的假设,而这大部分来自于缺乏沟通。 举个例子:现在有多少人在写智能合约时知道 ETH 可以在不调用回退函数的情况下被发送到合约中,即使该函数是不可支付的(non-payable?)? 它可以通过 SELFDESTRUCT 调用完成发送,余额被直接发送,而不是作为合约调用的一部分。 简单的例子:写一个测试,试图从一个你不持有余额的合约中提取余额,确保它恢复原状。
我们把这种同一个合约可能存在多个具有相同名称的变量,这种变量称为影子变量。 在更复杂的合约系统中,这种情况可能不会引起注意,并且随后可能引起某些安全问题。 如想像一下这种场景: 带有变量 x 的合约 A 可以继承同样定义了状态变量 x 的合约 B,这将导致 x 变量 的两个不同版本。其中一个从合约 A 访问,另一个从合约 B 访问。 这种场景下极容易出现变量隐藏的安全问题。 在 Solidity 编码中,变量隐藏常出现的场景包括: 同一个合约中,不同特定作用范围的变量。 继承关系的多个合约中,不同合约中具有相同名称的变量。 在编写更复杂的合约系统时,要时刻注意上面的两种场景,可能会由于忽视并随后导致变量隐藏安全问题。对于这两种场景分别用下面的代码进行演示。 2. 安全建议 变量隐藏常出现的两类场景: 同一个合约中,不同特定作用范围的变量。 继承关系的多个合约中,不同合约中具有相同名称的变量。 对于场景 1, 在开发环境中,编辑器会提示如下的影子变量的风险。
一些概念 满足“条件竞争”的发生条件 并发访问:对同一个合约发起的调用的交易可以被“并发”的发生,虽然这些交易会被放进交易池线性执行,但是这些交易的执行顺序并不能得到保证。 共享对象:对于一个合约来说,合约的Storage变量就是所有合约函数调用中都能访问的共享对象 写操作:对Storage变量的更新,就是对共享对象的写操作 智能合约的特点 矿工在交易打包前(智能合约真正执行前 ,矿工可能选择对自己有利的打包顺序,而不会带来任何的后果 如果某个重要而秘密的值通过合约的参数传递,矿工可能发起中间人攻击 普通用户可以通过提高gas price的方式,尽可能尝试改变交易顺序,发起竞争条件 漏洞合约分析 ? tokens) 函数在用于授权用户转账额度,在owner修改用户的转账额度的时候,当该操作被用户监听到的时候,可以增大gas price提前转走这比额度 漏洞预防 对于提高gas price的行为:在合约中设置最高的
文章源自【字节脉搏社区】-字节脉搏实验室 作者-毕竟话少 描述:漏洞合约中某个函数中,使用call()方法发送eth,若eth的接收者为一个合约地址,则会触发该合约的fallback()函数。 若该合约是攻击者的恶意合约,攻击者可以在fallback()函数中重新调用漏洞合约的上述函数,导致重入攻击 核心问题:重要的合约变量在“重入”的过程中没有被修改,从而绕过了限制 ? wei ETH,这里受害者合约ReentrancyGame就部署完成了) 攻击者合约部署ReentrancyAttack(攻击者合约),由于漏洞合约地址在提现的时候需要一定的ETH,所以这里在设置ReentrancyAttack 即可部署攻击者合约,部署完成后点击checkBalance查看当前账户余额为5 wei ETH,说明攻击者合约部署完成了 漏洞攻击-点击ReentrancyAttack(攻击者合约)attack即可攻击 漏洞预防 在将 Ether 发送给外部合约时使用内置的 transfer() 函数 。transfer转账功能只发送 2300 gas 不足以使目的地址/合约调用另一份合约(即重入发送合约)。
因此,每一个外部调用都会有潜在的安全威胁,尽可能的从你的智能合约内移除外部调用。当无法完全去除外部调用时,可以使用这一章节其他部分提供的建议来尽量减少风险。 被调用的外部智能合约代码将享有所有剩余的gas,通过这种方式转账是很容易有可重入漏洞的,非常 不安全。 当你自己的函数调用外部合约时,你的变量、方法、合约接口命名应该表明和他们可能是不安全的。 () 是不安全的。 安全相关的文件和程序 当发布涉及大量资金或重要任务的合约时,必须包含适当的文档。
这次我们将了解如何访问合约中的私有数据(private 数据)。 目标合约 话不多说,直接上代码 图片 这次我们的目标合约是部署在 Ropsten 上的一个合约。 #code 漏洞分析 由上面的合约代码我们可以看到,Vault 合约将用户的用户名和密码这样的敏感数据记录在了合约中,我们知道合约中修饰变量的关键字仅限制其调用范围,这也就间接证明了合约中的数据均是公开的 ,可任意读取的,将敏感数据记录在合约中是不安全的。 : 图片 这样我们就成功的将合约中的所有数据读取完成。 由此可见,合约中的私有数据也是可以读取的。 总结 大家可以看到,合约中的私有数据也是可以读取的,所以一定不要将任何敏感数据存放在合约中哦。
算术精度安全问题 了解完上面Solidity的特性以及算术的运算优先级问题之后,我们下面来讨论一下本期正题——算术的精度安全问题。 确实,之前是定义了,但是这里就是在问,到底再编写智能合约时是先把同级运算中的乘法放到前面还是先把除法运算放到前面呢?也许,有读者已经发现问题了! 上面的合约中test函数的左右只是根据用户输入的a,b,c的值进行数值运算,之后返回result的结果,下面我们将a,b,c依次赋值如下: a:5 b:2 c:10 ? 而且当数量级达到一定程度时引起的误差将会更加大~ 安全思考 1、到底是该先乘法运算还是先除法运算呢? 游戏合约中的游戏币的兑换功能、货币的买卖 文末小结 智能合约在发布之前应该在本地针对合约中的功能逻辑部分进行多次测试,并用不同的测试数据进行多次测试,同时建议对合约的安全性进行安全审计,合约开发没小事,
其结果是利用智能合约漏洞把资金耗尽,从而降低人们对这个未来无信任的去中心化基础设施的信任。因此,智能合约专家也需要检查清单。 本篇文章从不同来源整理了 101 个智能合约安全陷阱和最佳实践的清单。 我相信这份方便的 "安全智能合约检查清单 "将有助于开发者/审核员在以太坊上使用 Solidity 构建更安全和稳健的智能合约。 智能合约安全检查清单 Solidity 版本。 使用非常老的 Solidity 版本,无法从错误修复和较新的安全检查中获益。使用最新版本可能会使合约容易受到未发现的编译器错误的影响。 代理合约中的覆盖函数防止逻辑合约中的函数被调用。(见此处[132]) 总结 这篇文章从广泛引用的资料中整理了 101 个基本智能合约安全陷阱和最佳实践的清单。 智能合约开发者/审核员/协议的安全负担是巨大的。
描述:变量在参与运算的过程中,运算结果超出了变量类型所能表示的范围,导致实际存储的计算结果出错 核心问题:非预期的整数溢出将导致智能合约运行出错,影响合约的可靠性和安全性 基础知识 整数溢出的分类 整数上溢 漏洞合约分析 pragma solidity ^0.4.24; contract IntOverflow{ function addNumber(uint a, uint b) public
block.coinbase block.difficulty block.gaslimit block.number block.timestamp 使用区块相关属性作为随机数种子,是一种常见但是非常不安全的方式 ,其不安全在于,这些数据对于同一个transaction中的合约调用是可预测的。 msg.sender随机预测 使用msg.sender做为随机数种子的安全风险在于,该数据是用户可控的。若随机数种子一旦可以被攻击者选择或控制,就会使随机数面临被预测的风险。 ; } emit LuckyLog(lucky_number,guess); return lucky_number; } } 漏洞点:使用了不安全的 编译完成后会出现2个合约分别为RandomGame、AttackRandom部署 将AttackRandom合约中setTarget设置为RandomGame合约地址(0xdc0…46222) 点击attack