• 智能合约的安全


    智能合约的安全问题一直是编写智能合约的关键点。多数的智能合约都是开源的,源码公布更容易被黑客找到攻击的漏洞。 
    这里将一些常见的,易犯的错误。首先我们先看看下面这段代码:

    contract text{
        address owner;
        function userWallet() public{
            owner == msg.sender;
        }
        
        function transferto(address add,uint num) public payable{
            if(tx.origin == owner){
                add.transfer(num);
            }
        }
    }
    

      

    这里先讲讲其中tx.origin和msg.sender不同。msg.sender指的是调用合约的地址,而tx.origin指的是发起transaction的地址。举个例子,看下面的代码。

    pragma solidity^0.4.7;
    contract c1{
        address add1;
        address add2;
        function findAdd() public {
            add1 = msg.sender;
            add2 = tx.origin;
        }
        function getAdd1() public returns(address){
            return add1;
        }
        function getAdd2() public returns(address){
            return add2;
        }
    }
    contract differ{
        address public a1;
        address public a2;
        function f1() public {
            c1 c = new c1();
            c.findAdd();
            a1 = c.getAdd1();
            a2 = c.getAdd2();
        }
    }
    

      

    执行完合约后,a1就是合约differ的地址,而a2是调用合约diiffer的地址,也就是发起transaction的地址。上面简单讲了tx.origin和msg.sender的区别。接下来我们回到第一个合约中,这个合约实现了一个转账的功能·。但这个合约存在bug。黑客可以利用这个漏洞进行攻击。比如下面这段代码

    contract attack{
      address hack;
      constructor() public{
        hack = msg.sender;
      }
      function () external{
        text(msg.sender).transferto(hack,msg.sender.balance);
      }
    }
    

      

    只要让第一个text合约就会触发attack合约中的匿名函数,这时就会向hack地址转账了。因此在text合约中应该使用msg.sender而不是tx.origin。

    接下来还有一个不容易被找出来的错误,比如下面的合约

    pragma solidity^0.4.7;
    contract fund{
        mapping(address=>uint) num;
        function transferto(address add)public payable{
            if(num[add] != 0){
                add.transfer(num[add]);
                num[add] = 0;
            }
        }
    }
    

      

    这个合约实现一个兑换的功能,可以将每个address中所占的数兑换成以太币,黑客可以实现这样一个合约

    contract attack{
        address hack;
        constructor()public{
            hack = msg.sender;
        }
        function () external {
            fund(msg.sender).transferto(hack);
        }
    }
    

      

    这样合约fund每次转账都会调用attack合约的匿名函数,而匿名函数中又会调用合约fund中的转账。便会一直重复,这时候为了防止这种情况。可以改成下面的代码

    contract fund{
        mapping(address=>uint) num;
        function transferto(address add)public payable{
            uint temp = num[add];
            if(temp != 0){
                num[add] = 0;
                add.transfer(temp);
            }
        }
    }
    

      

    将兑换的num在转账之前重置为0。这样即使用上述的代码进行攻击亦不会再次执行转账了。

  • 相关阅读:
    win8.1下解决Visual C++不兼容的方法
    Java文件File类学习总结
    Java可视化日历(Date类、DATe Format类、Calendar类综合运用),开发可视化日历小程序
    java时间日期类(Date、DateFormat、Calendar)学习
    使用SimpleDateFormat类来实现时间跟字符串的转化
    Java中运行时异常和非运行时异常什么鬼?
    Java构造器练习题
    Word中一条删除不掉的单或双横线的解决办法
    Java中常用类(包装类扩展知识)
    Java异常学习总结二
  • 原文地址:https://www.cnblogs.com/mambakb/p/10111220.html
Copyright © 2020-2023  润新知