Soildity作为编写智能合约的语言,已经被广泛的应用。但同时,开发者和用户也得到了惨痛的教训,智能合约的安全问题层出不穷。因此,我们总结了一些常见的Solidity安全问题。前车之鉴,后车之师,希望后来者能有所警惕。
未检查低级调用的返回值
其中的Solidity的更深层次的特点是低级别的功能函数call,callcode,delegatecall和send。它们在计算错误时的行为与其他的Solidity函数完全不同,因为它们不会继续向前同时不会导致当前执行的完全回滚。相反,它们将返回将Boolean 设置为false,代码将继续运行。如果未检查此类低级调用的返回值,则可能导致打开失败和其他不需要的结果。发送可能会失败!
代码案例
上面的代码是一个调用send忘记检查返回值时可能出错的示例。如果将ETH发送到不接受它们的智能合约(例如,因为它没有应付回退功的能),则EVM将用其替换其返回值false。由于在我们的示例中未检查返回值,因此函数对合约状态的更改将不会被还原,并且etherLeft变量将最终跟踪不正确的值:
相关事件
King of the Ether“纷争时代”
KotET游戏中,玩家需要发送给合约一些ETH,从而获得“王位”。只要拿到了王位,玩家就会被加到皇庭,并且永远地被记录在区块链上。更重要地是,后来的国王有权去获得新国王的ETH。随着国王数量增多,成为国王的代价也会越来越贵。如果14天过去了,还没有新的继承者,那么王位就会重置,并且游戏也全部重新开始。
KotET合约的正常运作(基本上)是这样的:
1.假设王位的当前价格是10 ETH。
2.你想成为国王/王后,所以你向合约发送10 ETH。
3.合约将您的10 ETH(少于1%佣金)发送给之前的国王/王后,作为“赔偿金”。
4.合约使你成为以太王座的新王/王后。
5.在这种情况下,宝座的新索赔价格上涨50%,达到15 ETH。
6.如果一个篡位者愿意支付15ETH,他们会让你成为国王/王后,并且你会收到他们的15ETH作为你的“赔偿金”。
基于以太坊的交易,例如向合约发送付款或签订合约,都要花费“gas”。消耗的“gas”量取决于您调用的合约的操作类型(以及合约数量)。这种“gas”是支付给矿工的小额支付,有助于提供Etherum网络和区块链存储。gas由“外部拥有的账户”支付,该账户盯着交易。在进行交易时,交易需要包含一点gas(未使用的gas将被退还)。
那什么时候会出错?
KotET游戏在所有情况下都表现正确,除了它向“合约账户”发送付款时,例如以太坊Mist“基于合约的钱包”为例。
当KotET的合约向“合约账户”发送付款时,它仅包含了少量的gas。对于以太坊Mist“基于合约的钱包”合约而言,这并不足以成功处理付款 ,相反,付款失败了。
当钱包合约未能处理KotET合约发送给它的付款时,支付的ETH被退还给KotET合约。KotET并不知道付款失败并继续处理,尽管补偿金尚未发送给前任君主,但仍然会通知已到账。
总结
开发人员在编写合约时要考虑到这个问题,同时可以考虑用通throw函数将全额退款发送回,而不是使用send/call。同时在合约上线前要进行严格的审计,保证安全。