本文主要总结以太坊智能合约的安全漏洞。新加坡国立大学的Loi Luu提出了现在的智能合约存在的几种安全漏洞。然而,由于智能合约目前还只是初级阶段,相信各种安全问题会不断的发现。
智能合约中的安全漏洞交易顺序依赖合约
交易顺序依赖就是智能合约的执行随着当前交易处理的顺序不同而产生差异。例如,有两个交易T和T[j],两个区块链状态S[1]和S[2],并且S[1]状态处理完交易T[j]后才能转化为状态S[2]。那么,如果矿工先处理交易T,交易T调用的就是S[1]状态下的智能合约;如果矿工先处理交易T[j]再处理交易T,那么由于先执行的是T[j],合约状态就转化为S[2],最终交易T执行的就是状态S[2]时的智能合约。
攻击方法举例:
攻击者提交一个有奖竞猜合约,让用户找出这个问题的解,并允诺给予丰厚的奖励。攻击者提交完合约后就持续监听网络,如果有人提交了答案的解,此时提交答案的交易还未确认,那么攻击者就马上发起一个交易降低奖金的数额使之无限接近0。当矿工处理这两个交易时,当前交易池就有两个待确认交易:一个交易是提交答案,一个交易是更改奖金数额。如果矿工先处理的是敌手更改奖金的交易,而敌手可以通过增加交易费用让矿工先处理自己的交易,那么等到矿工处理提交答案的交易时,答案提交者所获得的奖励将变得极低,敌手就能几乎免费的获得正确答案。
时间戳依赖合约
矿工处理一个新的区块时,如果新的区块的时间戳大于上一个区块,并且时间戳之差小于900秒,那么这个新区块的时间戳就是合法的。这是以太坊协议所规定的。时间戳依赖顾名思义就是指智能合约的执行依赖当前区块的时间戳,随着时间戳的不同,合约的执行结果也有差别。
攻击方法举例:
如果有一个抽奖合约,要求由当前的时间戳和其它可提前获知的变量计算出一个“幸运数”,与“幸运数”相同的编码的参与者将获得奖品。那么矿工在挖矿过程中可以提前尝试不同的时间戳来计算好这个“幸运数”,从而将奖品送给自己想给的获奖者。
误操作异常
在以太坊中,一个合约调用另一个合约可以通过send指令或直接调用另一个合约的函数。然而在调用过程中可能会出现错误,调用的合约就会回退到之前的状态。那么这个异常就可能无法很好地被调用者获知,这取决于调用方式。例如,通过send指令调用的合约应该通过检查返回值来验证合约是否被正确执行。
攻击方法举例:
有个名叫KingOfTheEtherThrone(KoET)的智能合约:用户可以通过一定数量的以太币成为“以太币国王”,支付的数额由现任国王决定。很显然,当前国王可以通过买卖国王获得利润。当一个用户声称为国王后,合约就发送赔偿金给现任国王,并指定这个用户为新的国王。然而,这个合约并没有检查支付赔偿金的交易的结果。 这样一旦合约在执行过程中产生了异常,现任国王就有可能同时失去王座和赔偿金。
可能的攻击方式就是敌手故意超出调用栈的大小限制。以太坊虚拟机规定调用栈的深度为1024。敌手在攻击之前,首先调用自身1023次,然后发送交易给KoET合约,这样就造成了合约的调用栈超出了限制,从而出现了错误。合约出错后,因为这个合约没有检查合约的返回值,那么如果合约在发送赔偿金给现任国王的过程中出现了异常,那么现任国王极有可能失去王座和赔偿金。
可重入攻击
在以太坊中,当一个合约调用另一个合约的时候,当前的操作就要等到调用结束之后才会继续。这时,如果被调用者需要使用调用者当前所处的状态,那么这就产生了问题。
著名的DAO攻击事件就是因为这个漏洞而发生的。