美文网首页matter实验室
关于ERC20 Token智能合约的SafeMath安全

关于ERC20 Token智能合约的SafeMath安全

作者: 蟲哥 | 来源:发表于2018-08-07 16:57 被阅读0次

    前言

    浅谈 BEC的合约漏洞

    • 查阅BEC的智能合约代码,BEC的合约漏洞是batchTransfer函数的数据溢出。BEC 直接使用普通的加减乘除符号,缺少溢出判断,这就造成数据溢出的隐患。
    • uint256 amount = uint256(cnt) * _value; 如果 cnt = 2, _value=2^255,那么 amount = 0。因为溢出后,计算机取后面256位(都是0)。
    //合约地址:https://etherscan.io/address/0xc5d105e63711398af9bbff092d4b6769c82f793d#code
    //合约代码
    function batchTransfer(address[] _receivers, uint256 _value) public whenNotPaused returns (bool) {
        uint cnt = _receivers.length;
        uint256 amount = uint256(cnt) * _value;
        require(cnt > 0 && cnt <= 20);
        require(_value > 0 && balances[msg.sender] >= amount);
    
        balances[msg.sender] = balances[msg.sender].sub(amount);
        for (uint i = 0; i < cnt; i++) {
            balances[_receivers[i]] = balances[_receivers[i]].add(_value);
            Transfer(msg.sender, _receivers[i], _value);
        }
        return true;
      }
    

    分析BNB 的 SafeMath源码

    乘法,仅限内部调用,返回 uint256

    • uint256 c = a * b; 容易溢出,比如 a=2,b=2^255 乘积 2^256 刚好溢出。结果取后面的256位(全为0),导致 c=0
    • 所以使用 (a == 0 || c / a == b),验证结果的一致性
    function safeMul(uint256 a, uint256 b) internal returns (uint256) {
        uint256 c = a * b;
        assert(a == 0 || c / a == b);
        return c;
      }
    

    除法,仅限内部调用,返回 uint256

    • assert(b > 0), 确保被除数不能为0
    • assert(a == b * c + a % b);防止溢出,验证结果的一致性
     function safeDiv(uint256 a, uint256 b) internal returns (uint256) {
        assert(b > 0);
        uint256 c = a / b;
        assert(a == b * c + a % b);
        return c;
      }
    

    减法,仅限内部调用,返回 uint256

    • assert(b <= a) 因为返回值需要是 正数,所以此处判断 b必须小于等于a
      function safeSub(uint256 a, uint256 b) internal returns (uint256) {
        assert(b <= a);
        return a - b;
      }
    

    加法,仅限内部调用,返回 uint256

    • assert(c>=a && c>=b); //验证结果: 两个正数相加,和一定大于每个加数
      function safeAdd(uint256 a, uint256 b) internal returns (uint256) {
        uint256 c = a + b;
        assert(c>=a && c>=b);
        return c;
      }
    

    总结:
    不要直接使用简单的 "+-*/" ,尽量使用 library SafeMath 中的函数,避免整数溢出的隐患。

    关于计算机处理乘除法的原理
    请参考:https://www.cnblogs.com/mamamia/p/7760341.html

    相关文章

      网友评论

        本文标题:关于ERC20 Token智能合约的SafeMath安全

        本文链接:https://www.haomeiwen.com/subject/rmwovftx.html