区块链-DAO合约攻击

378 阅读4分钟

著名的DAO合约攻击:经典的重入攻击

🤔本文主要介绍DAO重入攻击的技术逻辑以及避免,至于DAO组织、DAO概念,麻烦各位客官自行查阅

什么是重入攻击,从我的理解中,即在一次调用中循环调用转账的方法造成盗币的攻击方式 这次攻击是由于solidity开发者的逻辑问题被黑客抓住了漏洞,通过写一个攻击合约去循环调用提现的方法,盗走了很多的货币;

由于账号分为:合约账户和普通账户,solidity合约本身就是一个合约账户,我们可以通过合约代码去调用目标方法进行攻击

基于上述的概念,以及主要的一个方法,fallback函数,这个函数经过payable的修饰,则标记为该合约是一个能够接收eth转账的合约,如果没有这个修饰,当我们对该合约进行转账的时候会报错

fallback 函数的功能有下面这些特点:

它们是不命名的。
它们是被外部调用的(它们不能够被自己合约内的函数调用)。
一个合约中只有 0 个或者 1 个 fallback 函数,不会更多。
它们会在别的合约调用一个本合约中不存在的函数时被调用。
当 ETH 被发送给这个合约的时候,如果该交易没有 calldata 同时合约中没有 receive() 函数时,fallback 函数会被触发。在这个场景下,fallback 必须被标记为 payable 以使它可以被触发并且接受 ETH。
Fallback 函数可以包含自己的逻辑,因此攻击者就可以大显身手了

重点就在于Fallback 函数可以包含自己的逻辑,因此攻击者就可以大显身手了

被攻击的合约代码,以下用伪代码展示

首先:
    方法一:存入eth
    方法二:提现eth{
        1:条件1:调用地址的余额大于0
        2:执行转账方法
            msg.sender.call(value)
            调用者的余额=0;
        3:返回
    }
    

各位客官看出问题在哪了吗?

问题出现在方法二中,执行转账方法的顺序问题上

代码逻辑先执行了转账,然后重置了余额,于是被攻击了

由于转账的特性,当 ETH 被发送给这个合约的时候,如果该交易没有 calldata 同时合约中没有 receive() 函数时,fallback 函数会被触发

以下是攻击者的合约:

    方法一:实例化被攻击者合约A,执行A.存储的方法,存入1ETH
    方法二:提现方法:{
    
    执行A.提现的方法
    
    }
    方法三:
    function fallback() payable{
    
           如果合约A的余额大于0,此余额是合约中存储的货币总量,不是指攻击者的余额,因为合约账户也可以存储货币,在这个方法中执行
            条件:A.balances>0 则继续A。提现,否则return
    }


这里我复述一下攻击流程: 被攻击合约A,攻击者合约B 1、A.存储eth 2、B.提现eth---->调用A.提现----->A中执行转账->转账之后回退到B的fallback---->继续执行A.提现---->循环---->直到fallback中余额小于0,此时msg.sender.call(value)才退出,然后在A.提现中return

从始至终msg.sender.call只执行了一次,然后就是递归调用攻击了

如何避免,其他方法各位客官也可进行补充

1、修改逻辑,先更新余额再执行转账(不太推荐,怕转账失败)
2、使用msg.sender.transfer 或者msg.sender.send 此技术逻辑下篇文章介绍,核心是gas限制
3.  增加时间戳参数:在每个HTTP请求中加入`timestamp`参数,并将这个参数与其他参数一起进行数字签名。服务器在接收到请求时,会检查`timestamp`参数与当前系统时间的差值是否超过60秒。如果超出这个时间限制,服务器通常会认为这是一个非法请求。因此,即使黑客尝试重放请求,由于其发出的`timestamp`超出了正常请求的处理时间范围,这样的请求也会被服务器拒绝。

4.  引入随机字符串`nonce`参数:在`timestamp`方案的基础上,可以增加`nonce`参数。服务器需要存储过去60秒内的`nonce`参数集合。当黑客试图重放请求时,他们无法知道服务器已经记录了这个`nonce`。因此,即使是相同的数据(除了`nonce`),服务器也能识别这是重复请求并予以拒绝。
5.使用OpenZeppelin提供的[重入锁](https://so.csdn.net/so/search?q=%E9%87%8D%E5%85%A5%E9%94%81&spm=1001.2101.3001.7020)

ps,上述有不正确的地方欢迎各位客官指正,共同进步