经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 其他 » 区块链 » 查看文章
智能合约的安全
来源:cnblogs  作者:mambakb  时间:2018/12/14 9:16:03  对本文有异议

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

  1. contract text{
  2. address owner;
  3. function userWallet() public{
  4. owner == msg.sender;
  5. }
  6. function transferto(address add,uint num) public payable{
  7. if(tx.origin == owner){
  8. add.transfer(num);
  9. }
  10. }
  11. }

  

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

  1. pragma solidity^0.4.7;
  2. contract c1{
  3. address add1;
  4. address add2;
  5. function findAdd() public {
  6. add1 = msg.sender;
  7. add2 = tx.origin;
  8. }
  9. function getAdd1() public returns(address){
  10. return add1;
  11. }
  12. function getAdd2() public returns(address){
  13. return add2;
  14. }
  15. }
  16. contract differ{
  17. address public a1;
  18. address public a2;
  19. function f1() public {
  20. c1 c = new c1();
  21. c.findAdd();
  22. a1 = c.getAdd1();
  23. a2 = c.getAdd2();
  24. }
  25. }

  

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

  1. contract attack{
  2.   address hack;
  3.   constructor() public{
  4.     hack = msg.sender;
  5.   }
  6.   function () external{
  7.     text(msg.sender).transferto(hack,msg.sender.balance);
  8.   }
  9. }

  

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

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

  1. pragma solidity^0.4.7;
  2. contract fund{
  3. mapping(address=>uint) num;
  4. function transferto(address add)public payable{
  5. if(num[add] != 0){
  6. add.transfer(num[add]);
  7. num[add] = 0;
  8. }
  9. }
  10. }

  

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

  1. contract attack{
  2. address hack;
  3. constructor()public{
  4. hack = msg.sender;
  5. }
  6. function () external {
  7. fund(msg.sender).transferto(hack);
  8. }
  9. }

  

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

  1. contract fund{
  2. mapping(address=>uint) num;
  3. function transferto(address add)public payable{
  4. uint temp = num[add];
  5. if(temp != 0){
  6. num[add] = 0;
  7. add.transfer(temp);
  8. }
  9. }
  10. }

  

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

 

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号