智能合约开发学习笔记(2)

使用 Solidity 开发智能合约的安全建议

关于使用Solidity开发的智能合约安全建议

外部调用

使用assert()强制不变性

当断言条件不满足时将触发断言保护。断言保护经常需要和其他技术组合使用,比如当断言被触发时先挂起合约然后升级。(否则将一直触发断言,你将陷入僵局)

正确使用 assert(),require()revert()

require(condition) 被用来验证用户的输入,如果条件不满足便会抛出异常,应当使用它验证所有用户的输入。

assert(condition) 在条件不满足也会抛出异常,但是最好只用于固定变量:内部错误或你的智能合约陷入无效的状态。

小心整数除法的四舍五入

所有整数除数都会四舍五入到最接近的整数。 如果您需要更高精度,请考虑使用乘数,或存储分子和分母。

记住Ether可以被强制发送到账户

谨慎编写用来检查账户余额的不变量。

攻击者可以强制发送wei到任何账户,而且这是不能被阻止的(即使让fallback函数throw也不行)

攻击者可以仅仅使用1 wei来创建一个合约,然后调用selfdestruct(victimAddress)。在victimAddress中没有代码被执行,所以这是不能被阻止的。

不要假设合约创建时余额为零

攻击者可以在合约创建之前向合约的地址发送wei。合约不能假设它的初始状态包含的余额为零。

记住链上的数据是公开的

当开发一个依赖随机数生成器的应用时,正确的顺序应当是(1)玩家提交行动计划,(2)生成随机数,(3)玩家支付

权衡Abstract合约和Interfaces

在双方或多方参与的智能合约中,参与者可能会“脱机离线”后不再返回

不要让退款和索赔流程依赖于参与方执行的某个特定动作而没有其他途径来获取资金。

使Fallback函数尽量简单

谨慎编写fallback函数以免gas不够用。

明确标明函数和状态变量的可见性

明确标明函数和状态变量的可见性。函数可以声明为 external,public, internal 或 private。

Use modifiers only for assertions

仅在断言使用修饰符。不在方法使用。

使用修饰符代替函数(如isowner())中的条件检查,否则在函数内部使用require或revert。这使得您的智能合约代码更易于阅读和审计。

标明 payable 函数和状态变量

Solidity 从 0.4 开始,每个接受 ether 的方法都必须使用 payable 修饰符。

Declare variables and especially function arguments as address payable, if you want to call transfer on them. You can use .transfer(..) and .send(..) on address payable, but not on address.

将程序锁定到特定的编译器版本

pragma solidity 0.4.4;

使用时间监测合约的活动

区分函数和事件 (Solidity < 0.4.21)

为了防止函数和事件(Event)产生混淆,命名一个事件使用大写并加入前缀(我们建议LOG)。对于函数, 始终以小写字母开头,构造函数除外。

// bad
event Transfer() {}
function transfer() {}

// good
event LogTransfer() {}
function transfer() external {}

使用Solidity更新的构造器

更合适的构造器/别名:

selfdestruct(旧版本为’suicide)
keccak256(旧版本为sha3)。
require(msg.sender.send(1 ether)) => msg.sender.transfer(1 ether)

Be aware that ‘Built-ins’ can be shadowed

Avoid using tx.origin

The 15-second Rule

Multiple Inheritance Caution

Use interface type instead of the address for type safety

Avoid using extcodesize to check for Externally Owned Accounts

安全相关的文件和程序


参考链接

觉得文章不错就支持一下呗~

打赏二维码