協議明明有審計報告,為什麼還是會因為舊授權被掏空?
審計報告驗證的,是合約在審計當下這個時間點的程式碼邏輯,不是這個合約未來永遠不會出問題的保證,也不是所有跟這個合約互動過的用戶,授權額度都設得很保守。以 Li.Fi 為例,2024 年出問題的是合約本身後來被發現的漏洞,而不是審計沒做好——但真正決定損失規模的,是有多少用戶帳戶上,還留著先前核准過的無限額度授權。如果所有用戶當初核准的都是剛好夠用的額度,即使合約出現漏洞,攻擊者能拿走的也只有那一次交易需要的量,而不是整個錢包餘額。
這代表審計報告解決的是「合約邏輯本身有沒有漏洞」,而使用者自己手上留著多少舊授權,是另一層完全獨立的風險,不會因為協議審計過就自動變安全——這也是為什麼即使是知名、審計紀錄完整的協議,依然建議定期檢查並撤銷不再使用的授權。
如果我大部分授權額度都設定得剛剛好,是不是就完全不需要花時間去撤銷了?
設定剛好夠用的額度,確實已經大幅降低了單一漏洞造成的損失上限,這是正確方向,值得肯定。但這不代表撤銷這件事完全不需要做——舊授權即使額度有限,依然是一筆攻擊面:如果一個你很久沒用的協議停止維護、或合約權限被惡意接手,即使額度有限,也還是有機會被找到方法動用;另外,額度有限的授權,也可能被組合式攻擊利用——例如結合其他漏洞,把多筆有限額度授權疊加起來達到更大的損失。
更實際的考量是:授權清單愈長,你要花心力去記得、去辨識「這個 spender 地址到底是哪個協議、我還在不在用」的難度就愈高,一份放著十幾二十筆多年沒動過的授權清單,本身就會讓你難以判斷哪些是安全的、哪些已經過時該撤銷。比較務實的做法,不是要求自己每筆交易後都馬上撤銷,而是養成定期(例如每季)檢查一次授權清單的習慣,把明顯不再使用的協議授權清掉,讓清單本身保持在你有能力逐一辨識、逐一判斷的規模。
Permit 跟 Permit2 這種簽名授權機制,聽起來比較安全還是比較危險?
這要看用在哪個情境。Permit(EIP-2612)跟 Permit2 這兩個機制原本的設計目的,是解決傳統 approve 流程「必須先送一筆授權交易、再送一筆實際操作交易」這種兩步驟、要付兩次 Gas 費的麻煩——透過簽名取代其中一筆鏈上交易,理論上對合法使用場景而言,是更有效率、更省 Gas 的設計,不是為了規避安全機制而生。
但正是因為這個簽名不用付 Gas、也不會立刻顯示在區塊鏈瀏覽器上,才讓它變成釣魚攻擊愈來愈偏好的手法——受害者感覺自己只是「簽了一個名」,心理警戒程度遠低於「送出一筆交易」,實際上簽名核准的內容,效力等同於一筆傳統授權交易。所以機制本身沒有比較危險,危險的地方在於使用者對「簽名」這個動作的警覺心,普遍低於對「交易」的警覺心——判斷風險的重點不在於用的是哪種機制,而在於每次彈出簽名或交易請求時,有沒有認真核對裡面列出的 spender 地址、授權額度跟合約位置。
如果我發現自己已經累積了十幾筆從沒清理過的授權,該怎麼決定優先撤銷哪些?
第一個優先順序,是先看「目前剩餘額度」——如果 Etherscan 或 Revoke.cash 顯示某筆授權的數字接近天文數字,代表這是無限額度授權,這類授權對應的風險上限最高(一旦出事,可能是整個代幣餘額),應該優先處理。第二個優先順序,是看這個 spender 合約你還認不認得、還在不在使用——如果是一個你已經好幾個月甚至好幾年沒互動過的協議,不管額度大小,都值得先撤銷,因為你已經沒有持續在關注這個協議的安全狀況跟營運進度。
第三個優先順序,是看這筆授權對應的代幣本身的價值跟持有量——如果你錢包裡那個代幣的餘額很小,即使授權額度無限,實際能造成的損失也有限;反過來,如果是你錢包裡持倉最大的資產,即使授權額度看起來合理,也值得優先確認這個 spender 合約目前的安全狀況。撤銷本身需要付 Gas 費,所以沒有必要把清單裡每一筆都馬上處理,用「無限額度優先、久未使用優先、高價值資產優先」這三個角度排序,通常就能把最該處理的幾筆挑出來。
你在任何一個 DeFi 協議上進行第一次交易之前,通常都會先跳出一個叫做「授權」(approve)的確認視窗——你可能想都沒想就點了確認,因為不點就沒辦法繼續操作。這個動作做的事情,是允許一個智能合約在未來可以動用你錢包裡某種代幣的餘額,而且很多錢包預設請求的授權額度,不是「這次要用的量」,而是「無限量」(通常寫成 2^256-1 這個天文數字)。這代表只要這個合約的程式碼裡藏著漏洞,或者合約權限被攻擊者拿下,你當初核准過的那份授權,就足以讓對方在一筆交易裡把你錢包裡那個代幣的餘額全部轉走——不需要拿到你的私鑰,因為你早就親手把權限給出去了。
一個常見的誤解是,把錢包從某個網站上斷開連結,就等於解除了風險。實際上完全不是這麼一回事——授權(allowance)是寫在鏈上、屬於代幣合約本身的一筆紀錄,不是網站前端跟你錢包之間的連線狀態。斷開連結只是讓網站暫時看不到你的錢包地址,那份「某合約可以動用你代幣」的授權紀錄,會一直留在鏈上,直到你主動發送一筆交易去撤銷它為止。這也是為什麼查授權這件事,不能只看「我最近有沒有跟這個網站互動」,而要直接去鏈上查詢你的錢包地址,曾經核准過哪些授權、目前還有哪些仍然有效。
以 Ethereum 為例,最直接的免費工具是 Etherscan 內建的 Token Approvals 頁面:連上 etherscan.io/tokenapprovalchecker,點選「Connect to Web3」把錢包接上(僅供讀取查詢,不會要求簽署任何交易),介面會列出這個地址目前所有仍然有效的授權,包含每一筆授權的「原始授權額度」(Original Allowance)跟「目前剩餘額度」(Current Allowance)——如果目前剩餘額度顯示一個接近天文數字的數字,代表這是一筆無限額度授權。找到你想撤銷的項目,點選對應的「Revoke」按鈕,錢包會跳出一筆交易請求,這筆交易本質上是呼叫該代幣合約的 approve 函式、把額度重新設回 0,需要支付一筆 Gas 費才能生效——撤銷本身也是一筆上鏈交易,不是免費的。多鏈使用者也可以用 Revoke.cash、Debank 這類第三方工具,一次檢視多條鏈上的授權狀況。
無限授權會被拿來利用,不是假設性的擔憂。2023 年,硬體錢包廠商 Ledger 的 Connect Kit 元件遭到釣魚攻擊,誘導用戶簽署無限授權,導致資金被盜;2024 年,跨鏈協議 Li.Fi 的合約漏洞被利用,因為大量用戶帳戶上早已存在的無限授權而損失約 970 萬美元;同年,去中心化交易聚合器 ParaSwap 的 Augustus V6 合約出現漏洞,先前核准過授權的用戶因此受影響;穩定幣協議 SenecaUSD 因合約缺陷被攻擊者利用既有授權掏空約 650 萬美元;跨鏈橋協議 SocketDotTech(Bungee)因為輸入驗證不完整,讓帶有無限授權的用戶損失約 330 萬美元;流動性協議 ConcentricFi 則是因為可升級合約的控制權被攻擊者奪走,導致約 172 萬美元損失,事後官方公開建議所有用戶撤銷授權。這些案例的共通點是:問題出在協議自己的合約,但真正被掏空的資產,取決於受害者手上是否留著早就該撤銷的舊授權。
近年的釣魚攻擊,愈來愈少直接要求受害者送出一筆看起來明顯可疑的鏈上交易,而是改用 EIP-2612(Permit)或 Permit2 這類簽名機制——這種簽名不會立即出現在區塊鏈瀏覽器上,也不需要你支付 Gas 費,看起來像是「免費、無害」的一次簽名動作,實際上簽下去的內容,跟送出一筆傳統授權交易,效果完全相同。這代表檢查風險時,不能只留意錢包彈出「交易確認」畫面的時候,連錢包彈出「簽名請求」畫面時,都該仔細核對裡面列出的 spender 地址、額度與合約位置,而不是看到彈窗就反射性點下確認。