想象你开了一家老式社区银行。柜员小明有个“坏习惯”:帮客户取款时,他总喜欢先掀开金库数出钞票、递到对方手上,然后才慢悠悠地拿起账本划掉余额。一天,一个“机灵”的客户走进来,取出 100 块后,立刻把存折再次推进窗口:“我再取 100 块。”小明扫了一眼账本——上面的余额居然和取钱前一模一样——于是又数了 100 块递出去。就这样反复几次,客户几乎掏空了现金抽屉,账本上却还写着他那笔钱原封未动。 这不是段子,而是智能合约世界最臭名昭著的安全漏洞——重入攻击(Reentrancy Attack)的生动描绘。在区块链上,“柜员”是一次次自动执行的合约代码,“存折”是链上的余额状态。如果合约先向外转账(数钱)、再更新自己的状态(记账),攻击者就能在转账与记账之间的窗口期,通过回调函数一次次重新进入提款逻辑,把合约里的以太币搬空。从 2016 年震惊业界的 The DAO 事件(损失约 6000 万美元),到 2022 年 DeFi 领域的一连串被盗案,重入攻击始终高居智能合约安全审计榜单的榜首。这篇文章,就带你从“柜员为什么先数钱后记账”开始,一步步搞懂重入攻击的原理、变种、审计方法与防线设计。
对 AI 从业者而言,理解智能合约安全是进入链上 AI Agent、DeFi 自动化系统和 Web3 应用开发的关键防线。一个不经意的函数调用顺序错误,就足以让整个“代码即法律”的信任体系瞬间崩塌。掌握它,是你在区块链领域建立工程信誉的第一块压舱石。
可视化演示
展示重入攻击fallback回调重入原理、Slither静态扫描人工审查形式化验证三层审计流程、重入溢出访问控制时间戳漏洞分类及CEI模式ReentrancyGuard防御策略,含流动波形背景动画。
本节配有交互动效(进入视口后自动加载,约 3KB)。
合约基础认知
把智能合约想象成一台放在街角的自动售货机:你投入硬币(发起交易),按下按钮(调用函数),机器根据预设的逻辑吐出饮料(执行结果)。整个过程没有店员,不依赖任何人的承诺,而且一旦出货,钱币也不会退回。这台“售货机”部署在区块链上,代码就是它的全部脾气秉性——部署后无人可以篡改,所有人的交易都按同一套规则执行。
为什么它能获得信任?答案是“区块链信任基石”:每一笔交易都会被矿工打包成区块,由全世界的节点独立执行同样的字节码,最终达成共识。任何人想作弊,都绕不开全网大多数节点的校验。这种“多方验证、不可篡改”的机制,使得一份代码可以承载数千万美元的资产,也让“代码即法律”从口号变成现实。
在技术层面,合约的执行可以被归结为一笔交易引发的状态转移:
回到售票机的比喻:售货机如果把“找零”和“记账”分成两个动作,而中间的间隙又能被退货口反向伸进来的手触发,那这台机器迟早被懂得门道的人薅空。智能合约正是这样——先转账、后记账的坏习惯,造就了第一类系统性安全灾难。
- 状态 $S_t$当前区块链上的所有账户余额、合约存储数据的快照,好比银行打烊时账本上的全部数字。
- 交易 $T_x$用户签名后广播的指令,包含调用哪个合约、哪个函数,以及附带多少以太币和附加数据。它像客户递进窗口的取款条。
- 转移函数 $\operatorname{Apply}$以太坊虚拟机按字节码逐条执行、消耗 gas、触发转账与事件的过程,相当于柜员识别取款条、走向金库、取钱、记账的一系列动作。
- 新状态 $S_{t+1}$交易结束后全网一致认可的新世界状态,下一笔交易将以此为起点。如果 Apply 的过程中“转账”和“记账”被拆成两步,那么这个中间窗口就是重入攻击的温床。
重入攻击原理
现在把镜头拉回老式银行柜台,仔细看小明“先数钱后记账”的流程。他数钱的动作,类似于 Solidity 中合约调用外部合约的 call 指令——执行权会完整交给被调用的那一方。被调用的攻击者合约收到以太币时,会触发它的 receive() 或 fallback() 回调函数。如果攻击者在回调里再次调用同一个提款函数,就形成一次“重入”。
攻击面到底藏在哪?关键在于“外部调用机制”与“状态更新时机”的错位。一个典型的不安全提款函数是:先检查余额,再执行转账,最后才把账本上的余额扣掉。攻击者的取款交易触发了第一笔转账后,合约的状态变量仍是旧值。于是攻击者的回调函数再次发起提款,检查依然通过,第二笔转账又发出去了。这个过程可以递归进行,直到合约的以太币余额被提空。
这一漏洞的本质可以提炼为一个蕴含式:
理解了这个执行顺序后,“资金窃取路径”就一目了然了:攻击者每次重入都走一遍完整的提款流程,而每次检查看到的都是未更新的老账本。只要合约的真实余额足够,这条路径就能一直走下去,直到金库见了底。柜员小明的习惯不改,再厚实的家底也经不起“反复取款”折腾。
- 外部调用 $\operatorname{call}_{out}$合约通过
.call、.transfer或普通函数调用,把执行权交给另一个合约。被调用方可以运行任意逻辑,甚至可以反手再调用调用方。 - 状态更新 $\operatorname{state}_{update}$对合约存储变量写入新值,例如
balances[user] -= amount。在现实世界对应柜员在账本上划线扣款。 - 先后关系 $\prec$符号表示“严格先于”。
$\operatorname{call}_{out} \prec \operatorname{state}_{update}$意味着在转账完成、控制权归还之前,合约账本还没动过笔。 - 蕴含 $\implies$当前件成立时,结论必然成立——即合约处于可被重入攻击的脆弱状态。攻击者只需准备一个带回调的合约,并在回调中重复执行提款逻辑即可。
攻击手法分类
重入攻击经过多年演化,早已不是单枪匹马闯金库的简单把戏。不同的攻击者会选择不同的“撬锁姿势”。让我们把这几种手法逐一拆开。
单次重入攻击是最经典的形态:攻击者在同一个函数的回调中反复递归调用该函数自身,像一个人站在取款窗口前,取一笔、递存折、再取一笔,循环往复。第二种是跨函数重入攻击:攻击者发现某个函数更新状态后,另一个函数还没有同步——于是从 A 函数转入 B 函数继续薅羊毛,好比在同一家银行的不同柜台间来回穿梭,利用柜员之间信息不同步来重复取款。
跨合约重入攻击更复杂:攻击者利用多个合约之间的相互调用关系,让外部合约在回调中再次进入目标合约,形成跨合约的递归。而只读重入攻击则相对隐蔽——它不直接盗走资金,而是在一个“只读操作”尚未返回时,通过重入改变某些状态,让预言机或第三方观察者读取到不一致的账目信息,进而操纵依赖该数据的下游协议。
不论哪种手法,最终的目标都指向同一个数学本质:
这四种“撬锁姿势”有个共同点:都是利用“账本没跟上钱的速度”。柜员只要坚持“先记账、后数钱”,所有招式都会在第一步检查上碰壁。所以,分类的意义不止于认识攻击者,更在于为后面的审计与防御提供排查清单。
- 单次提款额 $v$每次调用提款函数索取的金额,必须大于零且不超过合约账本中显示的余额。
- 合约资金 $B$重入窗口内合约可供转账的真实余额。因为账本未更新,检查条件一直按初始余额判断。
- 重入次数 $n$对取款条件
$B_{\text{账本}} \geq v$反复满足的次数取整。账本余额始终是初始值,所以理论上可以把合约真实资金提光。 - 总窃取额 $\text{stolen}$将单次提取金额乘以次数。这解释了为什么重入攻击的损失通常呈整倍数放大,像蚂蚁搬家一样在几次回调内搬空整座金库。
安全审计实践
面对这些狡猾的撬锁者,安全审计就如同给银行做一次全方位体检。审计师们通常从“代码审查流程”开始:逐行阅读合约源码,标注所有外部调用点,追踪状态变量在每条路径上的更新顺序,找出是不是有“先数钱后记账”的地方。这个过程非常像医生询问病史、翻阅病历——需要足够的耐心与经验。
接着进入“动态分析工具”阶段。审计师会把合约部署到测试链上,运行真实的攻击脚本,观察资金是否真的能被反复提走。这类工具还包括模糊测试(fuzzing),它像是一个不知疲倦的顾客,随机生成各种取款组合,试图找出某个异常路径。还有符号执行引擎(如 Mythril),它把代码编译成数学约束,自动探索所有执行路径。
更深一层是“形式化验证”:把合约的安全性质写成数学定理,用证明器验证定理在所有状态下都成立。这相当于给银行建了一个数学模型,证明任何攻击序列都无法突破金库——前提是模型本身没建错。审计完成后,所有发现会汇总成“审计报告构成”:按严重程度分级(Critical / Major / Minor / Informational),并给出复现步骤与修复建议。
衡量审计是否到位,最直观的参数是执行路径覆盖率:
体检报告再厚,也防不住未来新出现的病种。审计报告的价值在于让决策者知道“哪些地方值得信任、哪些地方需要持续观察”。回到柜员的比喻:体检能让小明意识到自己有“先数钱后记账”的坏毛病,但要真正改掉它,靠的是另一套纪律——也就是下一节的防护机制。
- 全部路径 $P_{\text{all}}$合约所有函数、分支、循环、重入组合构成的全部执行轨迹。对复杂合约来说,这个集合可能指数级庞大。
- 已检路径 $P_{\text{examined}}$审计工具真正扫过、执行过或证明过的路径子集。
- 比值与百分比两者相除再乘 100%,得到一个直观的“体检完成度”。业界对核心资金路径的覆盖率要求通常在 95% 以上。
防护机制设计
治标更要治本。想要银行不再被“反复取款”的客户钻空子,最有效的办法是让每位柜员养成铁一般的操作纪律:检查、效果、交互,一步都不许乱。翻译成 Solidity 就是三段式:先校验条件(require),然后立即更新所有状态变量,最后才发起外部转账。这个顺序被简称为 CEI 模式,可以说是智能合约界的“职业素养第一课”。
第二道防线是“互斥锁设计”。OpenZeppelin 的 ReentrancyGuard 提供了一个 nonReentrant 修饰符:函数开始时把一个布尔锁变量置为 true,结束时再还原为 false。递归调用在进入函数时发现锁已锁上,直接 revert。这相当于在柜台上装了一面防弹玻璃——身份验证成功一次后,玻璃门就关上,直到这笔业务完全办完。
第三道防线是“Gas 限制策略”。把外部调用的 gas 限制紧一些,让回调函数没有足够余粮执行循环重入。但它不是万能药,某些低 gas 操作(如转账 2300 gas)依然可能完成回调。最后还有“资金隔离方案”:将核心资金与外部交互模块分开存放,即使某个模块被攻破,损失也被限制在隔离区,不会烧到金库主仓。
CEI 模式的正确性可以形式化表述为:
想一想:当柜员每次都在递出钞票前先把账本划掉,那位狡猾的客户再递十次存折,看到的也是一次次递减的余额。第三次时,余额已经不足,取款请求被礼貌拒绝。这就是 CEI 的威力——不是提高柜员的警惕,而是让整个流程从结构上不再给“窗口期”留位置。
- 安全断言 $\operatorname{safe}(f)$对任意函数 $f$ 的安全属性判定。它在代码层面不可直接调用,而是审计与形式化验证时使用的逻辑谓词。
- 检查 $\operatorname{Check}(f)$函数入口处的全部前置条件校验,如余额是否足够、参数是否合法。对应柜员第一步先看存折。
- 效果 $\operatorname{Effect}(f)$对存储状态的写入操作,如扣减
balances[user] -= amount。这是让“账本跟上现实”的关键一步。 - 交互 $\operatorname{Interaction}(f)$发起外部转账或调用,将资金或控制权交给外部实体。它必须排在效果之后,确保回调方再也看不到旧状态。
- 等价关系 $\iff$表示“当且仅当”。满足 CEI 顺序,函数在很大程度上可免于重入攻击;违反顺序,则必然存在可利用的窗口。
真实案例分析
理论讲得再多,不如看一场真实的“银行劫案”。2016 年,以太坊上最著名的 DAO 组织遭遇了重入攻击。攻击者利用了 splitDAO 函数中“先转账后记账”的漏洞:在递归回调中反复提取自己名下的以太币,最终盗走了约 360 万 ETH,按当时币价折算超过 6000 万美元。事件之大,直接导致以太坊社区分裂,硬分叉出了今天的 ETH 与 ETC。这是重入攻击第一次将“代码即法律”的信念逼到墙角。
时间快进到 2022 年,DeFi 的快速膨胀让同类漏洞变得更频繁。跨链桥合约成为重灾区:黑客利用合约间的相互调用与状态同步延迟,在一笔交易中重复兑换资产。例如 Harmony 跨链桥 Horizon 被盗约 1 亿美元,Wormhole 则损失了 3.2 亿美元——虽然它们不全是单纯的经典重入,但“回调改变状态”的核心手法如出一辙。
NFT 项目也没能幸免。部分市场合约在 NFT 转账时会回调持有者的 onERC721Received 美元函数,攻击者通过在回调中重新上架或转移资产,制造出“未收到但实际已转走”的混乱局面。这些案例共同揭示一个规律:凡是涉及外部调用与内部记账之间有时间差的合约,都是重入攻击的潜在猎物。
从量化视角看,这些付给黑客的“学费”相当沉痛:
回顾这 28 亿美元的教训,最昂贵的一句话是:漏洞从来不是“发现了才存在”,而是“存在了才被发现”。 柜员小明的坏习惯也许几十年都没出过事,但一旦遇到懂行的客户,一次失误就是灭顶之灾。链上资金没有事后追索,唯一的保险,就是把“先记账、再数钱”的铁律刻进每一行代码。
- 单事件损失 $\text{Loss}_i$第 $i$ 次攻击事件中,被黑客转走的资产价值。有的来自重入,有的来自跨链桥签名漏洞。
- 求和 $\sum_{i=1}^{m}$将 $m$ 个代表性事件逐项相加,用来估算行业整体损失规模。
- 累计总损失 $\text{Loss}_{total}$约 28 亿美元。数字背后是一个个项目方的信任崩塌和无数用户的真金白银。
- 教训启示安全不是一次审计就能终结的交付物,而是一条持续对抗的军备竞赛。每一代攻击手法的翻新,都在提醒下一代开发者:柜员的纪律必须从第一天就刻进代码里。
AI 应用场景
DeFi 协议上线前的 AI 辅助审计
阶段:安全检测与风险分析
解决的问题:传统智能合约审计完全依赖人工逐行读码,一个中等规模的 DeFi 协议需要 4 至 8 周,且人工容易漏掉跨函数的状态更新顺序问题。AI 辅助审计工具先用静态分析(如 Slither)扫描所有外部调用点,再用图神经网络建模函数调用关系,自动标注“先调用后更新”的可疑路径,供审计师优先复查。这样将重入漏洞的检出率从纯人工的约 65% 提升到 90% 以上。
具体案例:某借贷协议升级前使用 AI 辅助流水线,在 48 小时内自动锁定了 3 个疑似重入点。审计师逐一验证后发现其中 1 个为真实的高危漏洞——跨合约重入,可在单笔交易中抽干流动资金池。提前修复避免了一场预计超过 5000 万美元的事故。
链上实时攻击预警系统
阶段:异常检测与实时监控
解决的问题:合约部署后并非一劳永逸,新攻击手法不断出现。传统规则引擎只能匹配已知攻击特征,遇到新型重入变种时容易漏报。AI 模型通过分析交易的完整调用图和跨合约交互序列,学习“正常取款模式”的分布,一旦发现同一函数在极短时间内被高频递归调用且状态写入滞后,立即触发预警。
具体案例:某监控平台在 2022 年成功捕获了一次针对 NFT 市场合约的只读重入攻击尝试。攻击者尝试利用回调干扰市场挂单状态,AI 系统在攻击交易确认后 3 秒内发出告警,项目方随即暂停合约,挽回了约 1200 万美元的潜在损失。
Python 演示
class ReentrancySimulator: """用Python模拟智能合约重入攻击与CEI防御""" def __init__(self): self.balance = {} # 用户余额账本 self.vault = 0 # 合约金库总资金 self.call_count = 0 # 调用计数 def deposit(self, user, amount): self.balance[user] = self.balance.get(user, 0) + amount self.vault += amount def withdraw_unsafe(self, user, amount, depth=0): """不安全的提款: 先转账后记账, 可被重入""" self.call_count += 1 if self.balance.get(user, 0) < amount or depth >= 3: return # 先转账(模拟外部调用) self.vault -= amount print(f" 第{depth+1}次调用: 转账 {amount} ETH, 余额仍未更新") # 攻击者在转账回调中再次调用提款 self.withdraw_unsafe(user, amount, depth + 1) # 最后才记账 self.balance[user] -= amount def withdraw_safe(self, user, amount, depth=0): """安全的提款: 检查-效果-交互""" self.call_count += 1 if self.balance.get(user, 0) < amount: print(f" 第{depth+1}次调用: 余额不足, 拒绝提款") return # 先更新状态(记账) self.balance[user] -= amount print(f" 第{depth+1}次调用: 余额更新为 {self.balance[user]}, 转账 {amount} ETH") # 再交互(转账) self.vault -= amount # 转账后的重入回调会被余额检查拦住 self.withdraw_safe(user, amount, depth + 1) def run_unsafe(): print("=== 攻击未防护的合约 ===") v = ReentrancySimulator() v.deposit("attacker", 1) v.withdraw_unsafe("attacker", 1) print(f"金库剩余: {v.vault} ETH\n") def run_safe(): print("=== 攻击已防护的合约(CEI模式) ===") v = ReentrancySimulator() v.deposit("attacker", 1) v.withdraw_safe("attacker", 1) print(f"金库剩余: {v.vault} ETH\n") if __name__ == "__main__": run_unsafe() run_safe()
self.balance = {}用字典记录每个用户的账本余额,对应链上合约的mapping存储。self.withdraw_unsafe(user, amount, depth + 1)模拟攻击者 fallback 回调中再次调用提款函数,形成递归重入。withdraw_safe` 中先把 `self.balance[user] -= amount效果先于交互,递归进入时余额已不足以通过检查。
常见误区
误区我写的合约没有支付功能,也没有向用户转 ETH,所以不会有重入风险。
正解重入攻击的本质是“外部调用与状态更新顺序颠倒”,只要合约调用了另一个合约的函数(哪怕只是读取信息、调用 token 转移、触发 NFT 回调),执行权就会临时转移到对方手里。对方可以在回调中再次进入你的合约,制造状态不一致。很多非转账场景(如治理投票、市场挂单)一样会被跨函数重入或只读重入利用。
为何常见:人们总是把重入与“取钱”“转账”绑定在一起,因为最著名的案例都是金库被盗。其实“外部调用”才是真正的关键词。
误区只要给关键函数加上 `nonReentrant` 修饰符,重入攻击就彻底没戏了。
正解互斥锁只保护它所在的那一个合约实例。攻击者可以绕过锁,比如通过跨合约调用路径:一个函数加了锁,但它在内部调用了另一个没有锁的合约,再由那个合约回调目标函数;或者利用只读重入,在不对状态做任何写入的情况下制造信息不一致。锁是有效工具,但绝不能取代 CEI 模式与整体攻击面分析。
为何常见:ReentrancyGuard 是一个标准库,一行修饰符就能解决问题,这种便利性让人高估了它的覆盖范围,忽略了锁的边界只到合约边界为止。
误区合约已经花大价钱请知名审计公司做过了,报告里没有高危漏洞,所以可以放心上线。
正解审计是降低风险的过程,而不是零风险的保证。审计覆盖率、工具精度、审计师经验都会影响结果;而且新攻击手法层出不穷,审计完成时的“安全”不代表一年后依然安全。行业里不乏通过了多轮审计、上线后仍被攻破的案例。正确态度是:把审计当作起点,配合持续的监控、升级预案和漏洞赏金计划。
为何常见:人类大脑倾向于把“专家验证”当成“绝对正确”,尤其在花了钱、看了正式报告之后,很容易产生“保险已生效”的错觉。
误区EVM 对 call 的 gas 转发有限制,重入回调要消耗大量 gas,所以攻击不可能成功。
正解EIP-150 确实限制了 call 最多转发 63/64 的 gas,但这并不妨碍攻击者自带 gas 启动新的调用帧;而且某些操作(如纯 ETH 转账只需 2300 gas)所需 gas 很低,回调完全可以在有限 gas 内完成递归。2016 年 DAO 攻击发生时,攻击者的递归调用正是依托当时的执行模型持续到资金耗尽。把安全押注在 gas 限制上,无异于指望门锁自己生锈。
为何常见:人们读到关于 EIP-150 的技术文章后,容易把它理解成“所有外部调用都被卡了脖子”,忽略了 gas 限制只约束转发、不约束攻击者自己发起的交易。
面试题
Q1. 重入攻击得以成功的根本原因是什么?
- A.合约代码存在语法编译错误
- B.先更新状态后执行外部调用
- C.先执行外部调用后更新状态← 正确答案
- D.发起交易所附带的 Gas 太高
答案:C。重入攻击的根本原因是函数将“转账(交互)”放在了“余额扣减(效果)”之前,导致回调时账本仍显示旧余额。A 是低级错误,与重入无关;B 是安全做法;D 的 Gas 高低不决定漏洞是否存在。
Q2. 智能合约被部署到区块链后,以下哪种说法是正确的?
- A.部署者可以随时修改合约代码逻辑
- B.代码一旦部署便不可更改且自动执行← 正确答案
- C.每次执行都必须由人工点击确认
- D.只有合约部署者才能调用其函数
答案:B。区块链上合约字节码存储在不可变地址中,部署后无法修改,任何人满足条件都可以调用其函数,这就是“代码即法律”的基础。A 在绝大多数区块链上不成立;C 的执行由交易自动触发;D 过分限制了公开合约的调用范围。
Q3. 在“检查-效果-交互”(CEI)模式中,正确的执行顺序是?
- A.先转账,再检查余额,最后更新账本
- B.先更新账本,再检查余额,最后转账
- C.先检查条件,再更新状态,最后交互← 正确答案
- D.先检查条件,再交互转账,最后记账
答案:C。CEI 要求校验(Check)、状态更新(Effect)、外部交互(Interaction)严格依次执行。选项 C 完全符合。A 和 D 都让转账发生在记账之前,正是重入漏洞的温床;B 则在条件未校验前就改了账本,可能被非法参数利用。
Q4. 以下哪些技术可以用于防御重入攻击?
- A.使用互斥锁限制函数递归进入← 正确答案
- B.在外部调用前先更新所有状态← 正确答案
- C.完全禁止合约间的一切调用
- D.采用资金隔离减小损失范围← 正确答案
答案:ABD。互斥锁(A)直接阻止重入回调;先更新状态(B)是 CEI 核心,让回调无法通过检查;资金隔离(D)控制爆炸半径。C 虽然能杜绝重入,但以太坊上的合约协作几乎无法避免外部调用,属于因噎废食,且即使完美禁用也不实际。
Q5. 2016 年 The DAO 攻击事件中,黑客采用的主要漏洞类型是?
- A.利用整数溢出增发代币后套现
- B.利用拆分函数中的重入漏洞反复提币← 正确答案
- C.通过暴力破解私钥获取管理员权限
- D.利用短地址攻击绕过转账校验
答案:B。The DAO 的 splitDAO 在切割资产时先发送以太币再更新余额,黑客通过在回调中递归调用拆分函数,将属于自己的 DAO 代币反复兑换成以太币。整数溢出(A)、私钥破解(C)、短地址攻击(D)都是不同类型的问题,不是本次事件主因。
Q6. 只读重入攻击的主要危害是什么?
- A.直接转移合约金库中的全部资金
- B.让外部观察者读取到不一致的状态← 正确答案
- C.永久删除合约的存储变量和代码
- D.阻止其他用户发起任何交易
答案:B。只读重入不会“盗币”,而是让只读函数在状态尚未稳定的窗口期返回中间值,从而被预言机、链上策展人等下游读取方误用,间接操纵价格或治理结果。A、C、D 均非只读重入的能力范围。
Q7. 合约中的“外部调用”是指什么?
- A.用户在前端页面点击按钮的行为
- B.合约 A 调用合约 B 的函数的过程← 正确答案
- C.区块链节点同步区块数据的过程
- D.开发环境编译合约源码的行为
答案:B。外部调用指合约在执行过程中,通过函数调用或 call 指令将控制权交给另一合约。B 正确。A 是链下行为;C 是节点基础设施;D 是开发流程,均不发生在合约执行上下文内。
Q8. 智能合约安全审计中,动态分析手段包括以下哪些?
- A.将合约部署到测试网模拟攻击场景← 正确答案
- B.运行模糊测试自动生成随机交易← 正确答案
- C.用静态扫描工具识别可疑代码模式
- D.人工逐行推演函数调用顺序
答案:AB。动态分析是指实际运行合约代码来寻找漏洞:部署到测试网模拟攻击(A)和模糊测试(B)都满足。C 是静态分析,D 是人工审计,二者并不执行目标代码,因此不属于动态分析。
Q9. “代码即法律”在智能合约语境下的准确含义是?
- A.合约代码需要经过立法机关审批
- B.合约按代码逻辑自动执行且不受干预← 正确答案
- C.开发者须将合约上传到法院备案
- D.执行结果可以被链下机构随时撤销
答案:B。一旦部署,合约的行为完全由代码决定,任何第三方都无法在交易执行过程中干预,结果是确定且不可逆的——这是“代码即法律”的核心。A、C 将法律概念实体化了;D 与区块链不可篡改性相悖。
Q10. 关于重入攻击的变种,以下说法正确的是?
- A.跨函数重入发生在同一合约的不同函数之间← 正确答案
- B.只读重入不影响合约状态但影响下游读取← 正确答案
- C.跨合约重入必须依赖两个合约间的相互调用← 正确答案
- D.单次重入只需要一次外部调用即可完成攻击
答案:ABC。跨函数重入利用同一合约内两个函数的状态同步差异,A 正确。只读重入不写状态,但能让外部读取方得到不一致数据,B 正确。跨合约重入需要外部合约在回调中重新进入目标合约,形成跨合约递归,C 正确。D 错误:单次重入虽在“一次交易”中完成,但攻击本身至少需要两次提款调用——第一次触发,第二次在回调中重入,否则无法构成“重入”。