区块链Solidity安全-默认可见性漏洞

默认可见性漏洞说明

Solidity中的函数可以被可见性说明符修饰,可见性说明符会定义用户如何调用Solidity函数。可见性决定一个函数是否可以由用户或其他派生契约在外部调用、只允许内部调用或只允许外部调用。Solidity有四个可见性说明符,详情请参阅 Solidity 文档。为允许用户从外部调用函数,函数的可见性默认为 public

如果不恰当使用可见性说明符,或是忽略指定函数应该使用的可见性说明符,可能会造成合约的重大漏洞。

漏洞介绍

函数的可见性默认是 public。因此,不指定任何可见性的函数就可以由用户在外部调用。当开发人员错误地忽略应该是私有的功能(或只能在合约本身内调用)的可见性说明符时,就会造成默认可见性漏洞。

攻击演示

合约HashForEther:如果用户的以太坊地址的最后8个十六进制字符为0,将会得到Ether奖励。

HashForEther.sol:

contract HashForEther {
    
    function withdrawWinnings() {
        // Winner if the last 8 hex characters of the address are 0. 
        require(uint32(msg.sender) == 0);
        _sendWinnings();
     }
     
     function _sendWinnings() {
         msg.sender.transfer(this.balance);
     }
}

合约正常逻辑:用户调用合约方法 withdrawWinnings() ,如果用户的以太坊地址符合要求(地址十六进制的最后8位是0),将会自动调用 _sendWinnings() ,得到以太坊奖励。

但是由于函数 _sendWinnings() 没有被可见性说明符修饰,默认为public,任何用户都有权限直接调用函数 _sendWinnings() ,这样任何用户都可以不经过任何检查,直接获得奖励,进行默认可见性漏洞攻击。

漏洞预防

建议开发者总是指定合约中所有功能的可见性,即便这些函数的可见性本就有意设计成 public,这是一种很好的做法。最近版本的Solidity将在编译过程中为没有明确设置可见性的函数显示警告,以鼓励这种做法。

预防演示

改进后的HashForEther.sol:

contract HashForEther {
    
    function withdrawWinnings() public {
        // Winner if the last 8 hex characters of the address are 0. 
        require(uint32(msg.sender) == 0);
        _sendWinnings();
     }
     
     function _sendWinnings() private {
         msg.sender.transfer(this.balance);
     }
}

你可能感兴趣的:(区块链Solidity安全-默认可见性漏洞)