簡介
鑑於以太坊上 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 智能合約開發人員減輕重入威脅的一些建議:
- 在程式碼中 使用檢查-效果-交互模式 (Checks-Effects-Interactions Pattern)。
- 在使用任何會引入外部調用的第三方程式庫時要小心。對於 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 等卓越投資者處獲得了兩輪數千萬美元的融資。
官方 Twitter 帳號:https://twitter.com/BlockSecTeam



