迄今为止,发现的重要安全漏洞都是因为智能合约编写安全性考虑不周到引发的。所以智能合约的审查与优化是重中之重

一、常见漏洞

1、溢出(Overflows)和下溢(Underflows)

溢出,就是当一个数字增加到它的最大值以上。Solidity可以处理多达256位的数字(高达2²⁵⁶-1),所以递增1会得0。

  0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+ 0x000000000000000000000000000000000001
----------------------------------------
= 0x000000000000000000000000000000000000

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

  0x000000000000000000000000000000000000
- 0x000000000000000000000000000000000001
----------------------------------------
= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF

两种情况都很危险,但下溢情况更可能发生,例如在代币持有者具有X个代币但试图花费X + 1的情况下。如果代码不检查这种情况的化,攻击者可能最终会被允许花费比他拥有的更多的代币,并且获得最大余额。

历史上的重大漏洞:一行代码蒸发了 ¥6,447,277,680 人民币!

2、可见性(Visibility)

简而言之就是控制好合约方法的访问权限,就像Java中的private,public等一样。

solidify合约可见性范围:

公共(Public)函数可以被任何人调用(被合约里的函数、继承合约里的函数、或者外面的用户)。

外部(External)函数只能从外部访问,意味着它们不能被合约里的其他函数调用。下面的要点不能编译,cannotBeCalled的外部可视性不允许它被合约里的函数调用(但它可以被别的合约调用)。

私有(Private)和内部(Internal)函数更简单:private是只能在该合约里使用,而internal提供了一个更宽松的限制,它允许从母合约处继承的子合约使用那个函数。

那就是说,除了需要外部交互的时候,设置你的函数为private或者internal。

注意:你使用智能合约的所有事情,都是公共可见的,即使是局部变量和标记为private的状态变量。

3、delegatecall(): parity事件

引述solidity文件:

“Delegatecall和信息调用,除了目标地址的代码要在请求调用的合约的上下文中执行之外,是完全一样的。msg.sender和msg.value不改变他们的值。 这意味着合约可以在运行时动态加载来自不同地址的代码。存储、当前地址和余额仍都取决于请求调用的合约,只有代码来自被调用合约。”

该函数能无条件的调用合约内的任何一个函数. 这个低级函数非常有用,因为它是实现库和模块化代码的中坚力量。 然而,它打开了漏洞的大门,因为你的合同基本上允许任何人以他们的状态做任何他们想做的。

在下面的例子中,一个攻击者可以调用合约Delegate的公共函数pwn,而且因为这个调用发生在Delegation的上下文中,他们可以对这个合约宣布主权。

Parity黑客涉及两个不安全的可见性修改功能组合,以及用任意数据滥用delegate调用。易受攻击的合约的函数实现了delegatecall,并且一个来自其他合约,能修改主权的函数被设成公共的。这使得攻击者可以设计msg.data字段来调用易受攻击的函数。

至于msg.data字段里会包含什么,那会是你想要调用函数的签名。这里的签名指的是函数原型的sha3(keccak256的别名)散列的前8个字节。

In this case:
web3.sha3("pwn()").slice(0,10) --> 0xdd365b8b
If the function takes an argument, pwn(uint256 x):
web3.sha3("pwn(uint256)").slice(0,10) --> 0x35f4581b

delegatecall该方法要慎用,并且做好完备的权限控制

典型案例:parity事件
Parity多重签名钱包被盗事件之技术分析
3张图看懂Parity钱包新漏洞-上亿的安全课

4、可重入性(The DAO黑客事件)

Solidity的call函数当被带着value调用时,会发送所有它收到的gas。在下面的代码片段中,调用是在实际减少发件人的余额之前完成的。一个在TheDAO黑客事件发生时reddit上的评论很好地解释了这个漏洞:

简单来说,就好像银行出纳员在她把你所要求的钱全部给你之前,不会更改你的余额。“我能取出500美金吗?等一下,在那之前,我能取出500美金吗?” 等等等等。按照设计的智能合约只会在最开始检查你有500美金,一次,而且允许它们自己被打断

正如这里所详细描述的,修复方案就是先减少发送人的余额再进行价值转移。对于使用并行编程的人来说,另外一个解决方法就是用互斥锁,从而一起缓解各种竞争条件。

目前来说,使用require(msg.sender.transfer(_value))是处理这些情况的最好的方法。

另一个实例:

任何合约A与合约B的交互以及任何发送以太币都会把程序控制权交给合约B。这使得合约B在交互结束之前,可以回调A。举个例子,下面的代码有bug(这只是代码片段,不是完整的合约代码):

pragma solidity ^0.4.0;
// 这个合约包含bug,请不要使用
contract Fund {/// 映射合约的以太币股份mapping(address => uint) shares;/// 取回你的股份function withdraw( ) {if (msg.sender.send(shares[msg.sender]))shares[msg.sender] = 0;}
}

这个问题不是很严重,因为send也有gas限制,但是依旧暴露出一个问题:以太币交易总是伴随着代码执行,所以接收者可能是一个会执行withdraw函数的合约。这会使得它可以多次取回金额,并且可以取回该合约的所有以太币。

为了防止重入,你可以使用下面的检查影响交互模式:

pragma solidity ^0.4.11;
contract Fund {/// 映射合约的以太币股份mapping(address => uint) shares;/// 取回股份function withdraw( ) {var share = shares[msg.sender];shares[msg.sender] = 0;msg.sender.transfer(share);}
}

注意,重入不仅对以太币交易有影响,而且可以是合约里的任何函数。另外,你必须考虑合约账户的多合约交互情况。一个被调用的合约可能会改变调用者的状态。

注:上面代码中还应该判断余额是否充足。上述两个案例都是:先减少发送人的余额再进行价值转移

The DAO的漏洞利用分析:

The DAO的漏洞利用分析
TheDAO被攻击事件考察报告
彭博社深度还原The DAO大劫案始末:过去已过去,未来仍需创造

二、其他注意的点:

2.1 sender和transfer

当发生错误时,transfer会抛出异常,sender返回false。我们一定要根据异常或者返回值来精确判断交易是否执行成功。

最佳实践是使用 “取回”模式而不是“发送”模式:即让币的接收者来主动索取他应该得到的币

2.2 如何获取发送者:msg.sender和tx.origin

msg.sender只能获取直接上级的地址,而tx.origin可以获取真正的交易发起者。所以避免使用tx.origin来进行权限控制,除非你确实搞明白了两者的区别及风险。

2.3 避免使用var

var可能会造成内存溢出,比如:

var length =300;for(var i = 0 ; i < length ; i ++){}

上述程序是一个死循环。因为var i = 0 ;i 默认是uint8 。所以i最大是2的8次方-1=255,255再加1,i又变为了0.

2.4 “检查生效交互”模式

对应上面的重入BUG

2.5、充分的容错及测试

三、其他参考资料:

3.1、OpenZeppelin合约安全解决方案

声明:OpenZeppelin可以简化我们的开发。因为它内置了很多东西,包括安全等方面。

现在使用OpenZeppelin的SafeMath库已经成为了一个标准。

openzeppelin官网

SafeMath库地址

OpenZeppelin中实现了安全的ERC20标准的代币 。我们可以多多借鉴参考

3.2、solidify安全考虑【官方】

官方原文

中文翻译(翻译的不太好)

安全考量——Solidity中文文档(5)

3.3、其他参考资料

如何使用Solidity编写安全的智能合约代码?

如何编写安全的solidify合约相关推荐

  1. 以太坊源码linux下如何编译,以太坊教程:搭建环境、编写编译一个智能合约

    本以太坊教程主要是介绍:搭建一个开发环境.编写编译一个智能合约. 以太坊是什么 以太坊(Ethereum)是一个开源的有智能合约功能的公共区块链平台.通过其专用加密货币以太币(Ether)提供去中心化 ...

  2. Truffle - 2 利用Truffle编写、测试智能合约并将其部署到不同的测试网络

    2 利用Truffle编写.测试智能合约并将其部署到不同的测试网络 2.1创建项目 建一个文件夹 mkdir truffle-project truffle init //初始化qinjianquan ...

  3. 基于星云链的智能合约与Dapp(四)——编写并运行智能合约

    一般智能合约需要以下几个步骤: 1.编写智能合约 2.部署智能合约 3.调用智能合约,验证合约执行结果 编写智能合约 Nebulas实现了NVM虚拟机来运行智能合约,NVM的实现使用了JavaScri ...

  4. Nebulas 101 - 03 编写并运行智能合约 ---》星云链开发

    Nebulas 3200 万奖金的 DApp 开发激励计划 注册地址:https://incentive.nebulas.io/cn/signup.html?invite=58jke 时间: 2018 ...

  5. 第6课 用SI编写Hello World智能合约,开启EOS之旅

    1,摘要 [本文目标] 通过本文实践,能够使用SI(Source Insight)编辑EOS的智能合约代码,并通过编译,执行来测试"Hello World"代码. [前置条件] 1 ...

  6. 以太坊教程:搭建环境、编写编译一个智能合约

    本以太坊教程主要是介绍:搭建一个开发环境.编写编译一个智能合约. 以太坊是什么 以太坊(Ethereum)是一个开源的有智能合约功能的公共区块链平台.通过其专用加密货币以太币(Ether)提供去中心化 ...

  7. 使用Atom编写以太坊智能合约

    以太坊智能合约开发环境 安装库 创建项目 编写合约 编译合约 部署合约 呼叫合约 结语 安装库 使用nodejs安装ethereumjs-testrpc和truffle.ethereumjs-test ...

  8. OpenZeppelin集成Truffle编写健壮安全的合约

    原文:http://truffleframework.com/tutorials/robust-smart-contracts-with-openzeppelin 因为智能合约往往涉及金钱,保证Sol ...

  9. 编写和部署智能合约:智能合约工具、remix、Truffle

    第五章 文章目录 第五章 一.智能合约工具 二.remix 三.Truffle 总结 一.智能合约工具 智能合约的编译环境就是solidity的编译环境,智能合约的执行环境就是EVM. 二.remix ...

最新文章

  1. 权限管理系统之模块管理
  2. failed to find romfile efi-virtio.rom
  3. 成本计算引擎动态规则解析技术详解
  4. 这让全场的chinaakd
  5. 论重写和里式替换原则(LSP)
  6. 计算机中汉字用什么表示什么,在计算机中汉字是用几个字节表示
  7. 【Vue2.0】—mixin混入 (十五)
  8. 初学Laravel框架与ThinkPHP框架的不同
  9. ENVI入门系列教程---一、数据预处理---4.1 遥感图像正射校正
  10. Android项目重构之路:界面篇
  11. jquery实现返回顶部的效果
  12. ArcGIS 10研究(二) 之Mobile新特性
  13. Android 多点触控
  14. 前端之搭建简单的Node服务器
  15. 第三章 迭代器(iterators)概念与traits编程技法
  16. 基于JAVA图书借阅系统的设计与实现计算机毕业设计源码+系统+lw文档+部署
  17. Intel® oneAPI Base Toolkit+Intel® oneAPI HPC Toolkit安装教程+环境变量设置
  18. TP5 控制器命名大小写问题
  19. bitbake hello world demo 实验
  20. 微信公众号最佳实践 ( 4.7)获取用户地理位置

热门文章

  1. iOS学习资料分享 -- 苹果官方iPhone应用高级开发课程(16集)
  2. 双十一3000元投影仪评测排名,性价比最高的投影仪是什么品牌
  3. 两轮差分底盘运动学模型
  4. android 5.1 keyguardhostview,android4.4的Keyguard心得
  5. python json转字符串_在python中将json转换为字符串
  6. json转字符串会存在null值字段会被忽略,如何避免
  7. soapui 乱码_SoapUI乱码问题处理方法
  8. 用hb配合php好用吗,达人测评福库CR-HB0810FB好用吗?怎么样呢?优缺点详细剖析评测...
  9. java单元测试之Mock测试编写
  10. Rust Wasm 图片转 ASCII 艺术