值得信赖的区块链资讯!
Solidity智能合约中的重入攻击
什么是Solidity智能合约中的重入攻击?了解区块链重入攻击是如何工作的,以及如何保护你的智能合约免受其影响。
重入攻击 是利用智能合约中的一个漏洞,在上一个执行完成之前重复调用一个函数, 这可能允许攻击者操控合约的状态。
本文将回答以下问题: 什么是Solidity重入攻击?将深入讨论重入攻击的机制、不同类型、缓解策略以及实际的智能合约示例。
那么让我们开始吧。
什么是Solidity重入攻击?
在Solidity智能合约的上下文中,重入攻击是指执行流被转移到一个外部合约,通常是通过外部调用(例如“fallback”函数或“onERC721Received”),允许函数(或另一个函数)被递归调用。 这使得外部合约可以重新进入合约,从而在执行完成之前操纵状态。
重入是一个状态同步问题,发生在状态在进行外部调用之前没有更新。这意味着当函数被重新进入时,状态与第一次调用时相同。
例如,如果该函数执行以下操作:
-
检查: 检查调用者的状态,例如要求调用者有足够的余额进行提现。 -
交互: 如果检查通过,执行外部调用,例如转账代币。 -
效果: 更新全局状态,例如在映射中减少调用者的余额。
由于状态是在执行外部调用后更新的,如果调用者是一个合约,并且在其fallback函数中重新调用同一个函数,他们仍然会通过步骤(1),使他们能够耗尽合约的资金。这段代码执行顺序,如下文所述,并不是避免重入攻击的正确模式。
这可能导致意外行为,允许攻击者操控合约的状态并可能耗尽其资金。
重入攻击导致合约资金被耗尽
智能合约重入攻击的类型
1. 单函数重入
这是最简单的重入攻击类型,发生在合约中的单个函数被重新进入时。这通常发生在函数修改合约状态,然后在没有首先更新其内部状态变量的情况下调用外部合约或发送Ether时。
2. 跨函数重入
跨函数重入发生在一个函数在更新状态之前执行外部调用,而外部合约调用另一个依赖于该状态的函数。这可能导致合约不同部分之间的意外交互,使攻击者可以利用一个函数的漏洞来操控另一个函数的状态。
3. 跨合约重入(也称为只读)
跨合约重入涉及多个合约之间的函数交互,其中状态是共享的。与之前一样,如果第一个合约中的共享状态在外部调用之前没有被更新,依赖于共享状态的合约可能会被重新进入。
4. 跨链重入
跨链重入虽然较少见,但涉及在不同区块链网络上部署的智能合约之间的交互。此场景可能发生在互操作性协议或去中心化交易所(DEX)中,后者促进跨多个区块链的交易。虽然机制与跨合约重入类似,但由于不同区块链生态系统之间的交互,复杂性增加。
欲了解有关跨链重入的更多信息,包括一个示例,请访问 Mateocesaroni撰写的以下博客。
5. 只读重入
也称为“只读外部调用重入”,指的是一种特定类型的重入漏洞,其中对另一个合约进行外部调用,但被调用合约的函数不会修改其状态。相反,被调用的函数读取来自调用合约的数据,然后重新进入调用合约,可能导致意外行为。尽管被调用的函数不修改状态,但它仍然可以影响调用合约的控制流或行为,从而带来安全风险。
有关只读重入的示例,请访问SunWeb3Sec的 DeFiVulnLabs常见智能合约漏洞库。
有关重入攻击代码示例,请访问Cyfrin Updraft的示例 漏洞库。
防范Solidity重入攻击的方法
1. 使用检查-效果-交互模式
确保在与外部合约交互或发送Ether之前进行状态更改。根据之前描述的示例,将步骤修改为遵循检查-效果-交互模式:
-
检查: 检查调用者的状态,例如要求调用者有足够的余额进行提现。 -
效果: 更新全局状态,例如减少在映射中的调用者余额。 -
交互: 如果检查通过,执行外部调用,例如转账代币。
让我们看看这在实践中是什么样子的:
mapping (address => uint) public balance;
function withdraw(uint amount) public {
// 1. 检查
require(balance[msg.sender] >= amount);
// 2. 效果
balance[msg.sender] -= amount;
// 3. 交互
msg.sender.call{value: amount}("");
// 注意:状态变更后始终应发出事件
emit Withdrawal(msg.sender, amount);
}
使用检查-效果-交互模式来防止重入攻击
2. 实现互斥锁或锁定
-
互斥(mutex)机制防止函数在同一交易中被多次执行。这通常通过布尔标志来实现,用于指示该函数是否正在执行,例如 isWithdrawing = true。 -
锁定可以用于“锁定”函数,确保在当前执行完成之前,另一个函数调用不能重新进入该函数。这防止函数在其状态仍被修改时被递归调用或从外部合约重新进入,因此降低了重入攻击的风险。 -
一种锁定的示例是重入保护:一个函数修饰符(在函数调用之前或之后执行的可重用代码块),最常用的保护是 Open Zeppelin的 ReentrancyGuard。该修饰符确保攻击者无法同时运行多个函数。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;
import {ReentrancyGuard} from"@openzeppelin/contracts/security/ReentrancyGuard.sol";
contractReentracyProtectedisReentrancyGuard {
mapping(address => uint) public balances;
functionwithdraw() externalnonReentrant {
uint balance = balances[msg.sender];
require(balance > 0, "余额不足");
balances[msg.sender] = 0;
(bool success, ) = address(msg.sender).call{ value: balance }("");
require(success, "提现失败");
}
}
3. 进行全面的代码审查和测试:
-
审计: 推荐进行多轮 智能合约审计,包括私密和竞争审计,可以显著减少发生重入攻击的几率。 -
全面测试: 审计并不是对漏洞的绝对保护。为了确保智能合约的安全,需要进行全面的测试,包括 智能合约不变量测试。
智能合约重入攻击示例
-
The DAO攻击: 2016年发生的最臭名昭著的重入攻击之一是对The DAO的利用,这是一个基于以太坊的去中心化投资基金。DAO的智能合约中的一个漏洞允许攻击者在合约更新其余额之前多次提取资金,导致约600万美元的以太坊被盗。该事件引发了以太坊区块链的一次争议硬分叉,以逆转未经授权的交易并恢复被盗资金。 -
Curve Finance: 在2023年7月30日,去中心化金融(DeFi)协议Curve Finance遭受了一次重入攻击,因Vyper编译器漏洞发生,导致近7000万美元被盗。
重入审计示例
以下代码片段显示了在HypercertMinter::splitValue中发现的一个漏洞,允许一个代币拆分成多个部分。
该函数调用SemiFungible1155::_splitValue,在写入减少的值到存储之前调用_mintBatch()。因此,没有遵循检查-效果-交互模式,因此该函数易受重入攻击。
_mintBatch()在_account是合约时调用_account.onERC1155BatchReceived();因此攻击者可以将执行流转移到攻击合约,并多次调用HypercertMinter::splitValue以分割相同的tokenId,从而铸造大量的部分。
/// @dev 将`account`持有的`_tokenID`的单位拆分到`_values`
/// @dev `_values`必须总和等于在`_tokenID`持有的总`units`
function_splitValue(address _account, uint256 _tokenID, uint256[] calldata _values) internal {
// ... //
uint256 valueLeft = tokenValues[_tokenID];
// ... //
for (uint256 i; i < len;){
valueLeft -= values[i];
tokenValues[toIDs[i]] = values[i];
unchecked {
++i;
}
}
//
// @audit CRITICAL 由于未遵循检查-效果-交互模式的重入攻击
//
// ERC1155._mintBatch()将在`_account`是合约时调用`_account.onERC1155BatchReceived()`。
// AttackContract.onERC1155BatchReceived()可以通过多次重新进入`_splitValue()`来劫持执行流,
// 从而铸造相同`tokenID`的大量部分,因为减少的`valueLeft`尚未写入存储,
// 在调用ERC1155._mintBatch()之前。
_mintBatch(_account, toIDs, amounts, "");
tokenValues[_tokenID] = valueLeft;
emit BatchValueTransfer(typeIDs, fromIDs, toIDs, values);
}
此漏洞来自于 Pashov对Hypercerts的审计。
有关此漏洞及其他重入审计发现示例的更多详细信息,请参考 Dacian的重入深入文章。
结论:什么是Solidity重入攻击
本文探讨了智能合约中的重入攻击,详细说明了其机制、类型、缓解策略以及诸如The DAO攻击和Curve Finance事件等实际示例,强调了安全措施和审计在防止此类攻击中的重要性。
进行协议审计可以显著降低发生此类攻击的概率。
比推快讯
更多 >>- Santiment:比特币鲸鱼群体近期持续增持,推动比特币站上 7.1 万美元
- 数据:分析:比特币鲸鱼近期重启积累,预计修正仍将持续
- Claude:未来两周非高峰时段及周末消息限额自动翻倍
- 曾做多价值 8400 万美元 BTC 及 ETH 鲸鱼平仓,转而现货增持 ETH
- 数据:当前加密恐慌贪婪指数为 14,处于极度恐慌状态
- 两艘印度油轮穿过霍尔木兹海峡,Hyperliquid 原油价格短时跌破 100 美元
- 特朗普称与泽连斯基达成协议“困难得多”
- MetaDAO 将于 3 月 26 日上线 P2P.me,最低融资目标 600 万美元
- 贝莱德数字资产主管:全球 ETF 前 20 仅比特币 ETF 亏损,90%投资者越跌越买
- 分析:G7史诗级石油释储或无法解决石油危机
- 数据:LA 涨近 10%,多个代币出现探底回升
- 数据:164.41 枚 BTC 从匿名地址转出,经中转后转至另一匿名地址
- RootData:ID 将于一周后解锁价值约 287 万美元的代币
- 加密交易所 BITGIN 洗钱案主犯在中国台湾被起诉,涉案金额逾 1.5 亿新台币
- Vitalik:应重新审视以太坊信标链与执行客户端分离架构
- Erik Voorhees 再次加仓黄金代币,目前仓位价值 2376 万美元,均价 4896 美元
- 英国前首相称比特币为“旁氏骗局”,认为其价值依赖市场信心
- 英国前首相称比特币为旁氏骗局,EricTrump 发文反驳
- 比特币突破 7.1 万美元,以太坊突破 2100 美元
- 英国前首相称比特币是旁氏骗局,Eric Trump 带头驳斥
- 以太坊合并后流通量已增加超 100 万枚,年化通胀率约为 0.24%
- 金融博客零对冲,VIX 指数与整体波动性脱节严重
- Anduril 创始人:美国缺乏对伊朗发动地面战的政治意愿,美国需要从世界警察角色中转型
- Scam Sniffer:某地址因签署钓鱼邮件损失逾 72 万美元 valBUSD 与 valTUSD
- 数据:Hyperliquid 平台鲸鱼当前持仓 34.18 亿美元,多空持仓比为 1.01
- USDH 发行方 Native Markets 将推出代币化保证金 pmUSDH
- 高端奢侈珠宝和腕表品牌 Jacob&Co.推出可挖矿腕表,限量 100 只
- Tether 近几个月内高频出手投资,已披露金额超 16 亿美元
- 中国山东女警撕开虚拟货币地下钱庄黑幕:锁定 12 名主要犯罪嫌疑人、100 余个资金账户
- 某鲸鱼卖出 634 枚 XAUT,获利约 25 万美元
- 分析:标普 500 期货流动性已较历史均值低 61%,数百万美元订单即可推动指数波动
- Galaxy 研究主管:若加密法案 4 月底前未过参议院委员会审议,2026 年通过概率将大幅下降
- Aave 正就“将年回购预算从 5000 万美元下调至 3000 万美元”进行投票
- 瑞士邮政银行扩展加密交易服务,新增 ARB、NEAR、SUI 等资产
- Aave 将推出 Aave Shield 功能,默认阻止价格影响超过 25%的 Swap
- 消息人士称美伊均无意停火,中东战事或持久化
- 以太坊基金会 OTC 向 BitMNR 出售 5000 枚 ETH,均价 2043 美元
- 巨鲸卖出 50 枚 BTC 买入 1693 枚 ETH,并 10 倍杠杆做多 LINK
- 美国法院维持美联储裁决,驳回 Custodia 申请主账户重审请求
- 特朗普:条件还不够好 目前并不准备与伊朗达成协议(金十数据 APP)
- 数据:ETH 当前全网 8 小时平均资金费率为 -0.0014%
- BTC 突破 71000 USDT,24H 涨幅 0.31%
- Polymarket 加密货币板块新增 DOGE、BNB、HYPE 价格预测
- 以色列拦截导弹库存被曝“严重不足”
- 以太坊基金会向 BitMine 出售 5,000 枚 ETH,价值约 1022 万美元
- 数据:过去 24 小时加密货币市值前 100 代币涨跌
- 数据:过去 24 小时全网爆仓 1.78 亿美元,主爆多单
- 黎巴嫩和以色列将在未来几天举行直接会谈
- 彭博社:BTC 正接近历史熊市底部区间,潜在底部区间为 4.5 万至 5.5 万美元
- 某巨鲸沉寂 2 个月后 20 倍杠杆做多 CL 原油,仓位价值 1152 万美元
比推专栏
更多 >>- 懂王:登陸那個島|0314 Middle East
- 懂王:那就大家一起難受吧|0313亞盤後
- 当黄金被「困」在迪拜,是时候旗帜鲜明「唱多」香港了
- 東大、波斯、阿拉伯【第七次/進展/能源變量】|0310東3.5
- 从 HSK 到 USDGO:香港两大持牌机构,开始「脱钩」
- There is no new boss YET
- New situation and new games|0305 Asian
- B52 Were on the way to Iran|0304 Middle East
- 开放独角兽门票:从 Robinhood 到 MSX,一场 Pre-IPO 的链上平权实验
- Big player's 『Trigger moment』|0227Europe
观点
比推热门文章
- 曾做多价值 8400 万美元 BTC 及 ETH 鲸鱼平仓,转而现货增持 ETH
- 数据:当前加密恐慌贪婪指数为 14,处于极度恐慌状态
- 两艘印度油轮穿过霍尔木兹海峡,Hyperliquid 原油价格短时跌破 100 美元
- 特朗普称与泽连斯基达成协议“困难得多”
- MetaDAO 将于 3 月 26 日上线 P2P.me,最低融资目标 600 万美元
- 贝莱德数字资产主管:全球 ETF 前 20 仅比特币 ETF 亏损,90%投资者越跌越买
- 分析:G7史诗级石油释储或无法解决石油危机
- 数据:LA 涨近 10%,多个代币出现探底回升
- 数据:164.41 枚 BTC 从匿名地址转出,经中转后转至另一匿名地址
- RootData:ID 将于一周后解锁价值约 287 万美元的代币
比推 APP



