智能合约的安全详解编程语言

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

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。这样即使用上述的代码进行攻击亦不会再次执行转账了。

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/20747.html

(0)
上一篇 2021年7月19日
下一篇 2021年7月19日

相关推荐

发表回复

登录后才能评论