返回部落格

安全的智能合約開發 — NFT 合約中的代碼重入問題

Code Auditing
2022年8月5日
閱讀約 4 分鐘

簡介

鑑於以太坊上 NFT 生態系統的繁榮以及相關安全問題的增加,我們將發布一系列部落格來介紹這些安全問題,並為開發人員提供一些確保合約安全的建議。在本篇部落格中,我們將介紹 NFT 合約中的重入(Reentrancy)問題,以及如何緩解相關漏洞。

什麼是重入

根據 維基百科

在計算中,如果一個電腦程式或子程序可以被多個處理器安全地並發執行,或者在單處理器系統中,在執行過程中被中斷並在其之前的調用完成執行之前被安全地再次調用(「重新進入」),則該程序或子程序被稱為可重入的。

在智能合約中,當一個函數執行了對另一個合約的外部調用,而該外部調用在原始調用返回之前又調用了原始函數(或其他函數)時,就可能發生重入。如果該外部調用由不受信任的實體(例如惡意合約)控制,則可能導致意外的結果。這是因為在某些函數中,結果取決於合約狀態。合約狀態通常會在外部調用之後更新,但函數的重入調用會使用舊狀態而不是更新後的狀態。

重入攻擊一直是智能合約中的一個普遍問題,例如 MakerDAO 攻擊、Uniswap 上的 ERC777 攻擊 以及其他案例(可在 BlockSec Academy 搜尋 Reentrancy)。

NFT 中的重入

對於 NFT 合約,存在一些開發人員可能忽略的隱式外部函數調用,它們包括 onERC721Received 和 onERC1155Received 函數。onERC721Received 函數旨在檢查接收合約是否能夠處理 NFT(以防止 NFT 被永久鎖定)。此函數在 ERC721 合約 的 safeTransferFrom 和 _safeMint 中被調用。ERC1155 合約 中也存在類似的功能。由於這些外部函數調用,合約開發人員可能在不知不覺中觸發重入。

單函數重入

單函數重入是重入攻擊最簡單的形式。在這種攻擊中,被重入調用的函數與原始函數相同。攻擊者可以在函數的第一次調用完成之前重複調用該函數。在 NFT 合約中,這通常發生在與 mint(鑄造)操作相關的函數中。

例如,某些 NFT 專案可能會給每個使用者一次免費鑄造 NFT 的機會,設定整個專案的總供應量上限,或設定單一使用者可持有的最大 NFT 數量。通常,這些限制會在實際執行鑄造操作之前進行檢查。但如果與這些限制相關的狀態是在 safeMint 函數之後更新的,攻擊者就可以重入此鑄造函數並繞過限制,因為相關狀態與該函數的第一次調用時相同。我們之前在部落格中發布的 HypeBears 重入攻擊 文章 就是一個例子。

一種更復雜的單函數重入發生在循環中使用 safeMint 函數且限制在循環開始前檢查時。在這種情況下,即使某些狀態在外部調用之前會自動更新,循環中剩餘的 safeMint 函數調用仍可能繞過驗證,因為循環已經開始,且驗證是在循環開始前進行的。

例如,在另一篇 文章 展示的範例中,mintNFT 函數會檢查使用者想要鑄造的 NFT 數量加上當前供應量是否會超過最大供應量。safeMint 函數在 onERC721Received 外部調用之前更新了總供應量。但攻擊者仍可利用此漏洞,因為 safeMint 函數每次只將總供應量增加 1。因此,如果攻擊者在循環中第一次 safeMint 函數調用時重入 mintNFT 函數,總供應量變為舊供應量加 1,而不是舊供應量加上第一次 mintNFT 調用將要鑄造的所有 NFT 數量。

跨函數重入

攻擊者不僅可以重新進入同一個函數,還可以進入另一個與原始函數共享狀態或依賴相同狀態的函數。我們在之前的部落格中詳細介紹了一些案例,例如 Revest 案例 和 OMNI 案例。

總結與建議

以下是供 NFT 智能合約開發人員減輕重入威脅的一些建議:

  1. 在程式碼中 使用檢查-效果-交互模式 (Checks-Effects-Interactions Pattern)。
  2. 在使用任何會引入外部調用的第三方程式庫時要小心。對於 NFT 合約,請務必謹慎對待 onERC721Received 和 onERC1155Received 函數的隱式回呼。

閱讀本系列的另一篇文章

關於 BlockSec

BlockSec 是一家開創性的區塊鏈安全公司,由一群全球知名的安全專家於 2021 年成立。公司致力於為新興的 Web3 世界提高安全性和易用性,以促進其大規模採用。為此,BlockSec 提供智能合約與 EVM 鏈的 安全審計 服務、用於安全開發與主動威脅攔截的 Phalcon 平台、用於資金追蹤與調查的 MetaSleuth 平台,以及協助 Web3 建構者在加密世界中高效航行的 MetaSuites 瀏覽器擴充功能。

迄今為止,公司已服務超過 300 家知名客戶,如 MetaMask、Uniswap Foundation、Compound、Forta 和 PancakeSwap,並從 Matrix Partners、Vitalbridge Capital 和 Fenbushi Capital 等卓越投資者處獲得了兩輪數千萬美元的融資。

官方網站:https://blocksec.com/

官方 Twitter 帳號:https://twitter.com/BlockSecTeam

訂閱最新動態
Bitget 3.875億美元鏈下違規事件:超越金鑰與合約的範疇
Security Insights

Bitget 3.875億美元鏈下違規事件:超越金鑰與合約的範疇

2026年9月24日,攻擊者利用第三方安全產品漏洞,獲取內部憑證並偽造提款指令,導致約3.875億美元從Bitget部分營運錢包(涵蓋Ethereum、其他EVM網絡、XRP Ledger、Zcash及TRON)轉出;私鑰及冷錢包未受影響。本文深入梳理事件路徑與資金流向,分析快速轉換為原生資產及生態恢復應對,提出機構縱深防禦框架,並說明授權區塊鏈滲透測試如何驗證跨層假設。

約1130萬美元損失:Multicall Router、Nostra|BlockSec Weekly
Security Insights

約1130萬美元損失:Multicall Router、Nostra|BlockSec Weekly

本報告涵蓋2026/09/14至2026/09/20期間,探討以太坊與Starknet上兩起合計損失約1130萬美元的安全事件。較大一起中,多重呼叫路由器將自身位址接受為分派目標,導致巢狀呼叫以路由器自身已授權身分而非外部呼叫者身分進入Safe錢包的Gateway模組,約2900枚`aEthrsETH`被轉出至攻擊者建立的Uniswap v4池。在Starknet上,Nostra預言機整合僅要求最少一個聚合來源,當三個設定價格來源中僅兩個達成聚合時,操縱的薄池報價與正常報價平均後將`NSTR`估值約49.52美元,支撐約350萬美元以高估抵押品借貸。

损失約3.2億美元:Liquid Network與Symbiosis遭攻擊事件 | BlockSec
Security Insights

损失約3.2億美元:Liquid Network與Symbiosis遭攻擊事件 | BlockSec

本報告涵蓋2026/09/07至2026/09/13,探討兩起造成約3.2億美元損失的安全事件,包括前份報告未提及、發生於2026/09/06的Liquid Network漏洞事件。較大者為該Liquid Network漏洞:Elements中的rangeproof驗證快取藉由雜湊四個欄位(其中兩個長度可變)串接而成金鑰,且未標示欄位邊界,導致某輸出的驗證結果被錯誤套用至另一個未經檢驗證明的輸出,使攻擊者得以憑空創造4,000枚無擔保L-BTC,並將幾乎全數兌回比特幣。在橫跨BNB Smart Chain、Ethereum與Rootstock的Symbiosis跨鏈橋比特幣路徑中,讀取比特幣存款的鏈下程式碼從存款人可自行控制的欄位取得其身份,並在未檢查手續費是否為負值的情況下自存款中扣除,使330聰的存款鑄造出`46,116,860,184.27388234 syBTC`;其須賣出所經之資金池僅有11.26 syBTC,致使流動性提供者與用戶損失約9.97 BTC(約77萬美元)。

Web3 最佳安全審計方

在上線之前驗證設計、程式碼與業務邏輯,對標業內最高安全標準。

BlockSec 審計
安全的智能合約開發 — NFT 合約中的代碼重入問題