安全的合約錢包 Recovery

如何設計安全的合約錢包 Recovery 機制

  • 作者:Nic Lin @ imToken Labs

  • 校對:imToken Labs

  • 封面來源:rawpixel.com @ freepik

  • 適合讀者:區塊鏈錢包開發者

  • 先備知識:

  • 閱讀小提醒:以下將視「帳戶」或「錢包」兩個詞為同義並將交互使用;另外「Contract Account」、「Contract Wallet」也會視為同義,都是指「合約錢包」


合約錢包的 Recovery 機制

Recovery 機制的角色

在合約錢包的 Recovery 機制中會有 Owner 及 Guardian 兩種角色。

  • Owner 是錢包的主人,也就是使用者。可以同時有多個 Owner,像是多簽錢包,但以下都會以單一 Owner 為例

  • Guardian 是負責進行 Recovery 的角色,使用者可以同時指定多個 Guardian 以及 Guardian 操作能生效的門檻值。以下描述 Guardian 的操作都會假設已經超過門檻值數量的 Guardian 的同意,不會再細分有無超過門檻值討論

不同於 EOA Recovery 中的 Guardian 可能會和使用者有複雜的互動,例如 Guardian 會負責保管使用者加密過的 Share 並在使用者需要時交還加密的 Share,讓使用者還原出私鑰、完成 Recovery。合約錢包裡的 Guardian 都是和合約進行互動來完成 Recovery,所以接下來的內容都是圍繞在 Owner 及 Guardian 兩個角色各自和合約錢包之間的互動而不是 Owner 和 Guardian 之間的互動。

在合約錢包 Recovery 中,Owner 和 Guardian 都是和合約互動
在合約錢包 Recovery 中,Owner 和 Guardian 都是和合約互動

Recovery 機制的操作

  • updateGuardians:Owner 可以透過 updateGuardians 更新 Guardian 的名單,新增新的 Guardian 或移除舊的 Guardian

  • resetOwner:Guardian 可以透過 resetOwner 更新 Owner 地址,也就是執行 Recovery

以上是 Recovery 機制裡的角色及相關操作介紹,看起來不會很複雜 – 兩個角色與兩種操作。但隨著引入對不同角色的信任假設(例如不相信 Guardian),就會需要加上不同的檢查措施與反制機制,這時 Recovery 機制就會越來越複雜。這也是本文的目的:藉由分析不同角色的安全假設並列舉出相對應的反制方法,讓 Recovery 機制的設計變得清晰、讓分析 Recovery 機制變得簡單。


Owner 及 Guardian 的安全假設

如果假設 Owner 和 Guardian 都是可信的話,那 Recovery 機制真的就會非常簡單,但 Web3 世界裡的使用者及開發者可不會輕易地做出這樣的假設。接下來會分別假設 (1) Guardian 可能是惡意的以及 (2) Owner 可能是惡意的(待會會解釋為什麼)兩種情況,並分別討論當有了這樣的假設,合約錢包的 Recovery 機制該怎麼配合做調整。

如果我們假設 Guardian 可能是惡意的

如果我們不放心 Guardian 有任意 resetOwner 的權力,可以在 resetOwner 裡加上時間鎖,在惡意 Guardian 觸發 resetOwner 時讓 Owner 有時間反應並取消 resetOwner

Guardian 觸發 resetOwner 並開始時間鎖倒數,時間鎖結束前 Owner 都可以直接取消
Guardian 觸發 resetOwner 並開始時間鎖倒數,時間鎖結束前 Owner 都可以直接取消

但請記得 時間鎖並不能免除對 Guardian 的信任,只要 Owner 沒有在時間鎖結束之前去取消 Reset,那 Reset 一樣會生效,惡意的 Guardian 一樣可以奪走使用者的錢包控制權

如果 Owner 沒有在時間鎖結束前取消,那一樣會失去錢包控制權
如果 Owner 沒有在時間鎖結束前取消,那一樣會失去錢包控制權

有沒有什麼辦法能夠免除對 Guardian 的信任?

答案是:沒有,這是因為「合約本身沒辦法知道使用者是否遺失私鑰」,所以它必須要授權 Guardian 有完全的權力來 resetOwner。除非我們能假設私鑰不會遺失。

但如果私鑰不會遺失,我們還需要 Recovery 機制嗎?雖然「私鑰不會遺失」這種假設非常少見,或甚至沒有實際意義,但錢包設計者在設計規則時還是會考慮到「私鑰遺失」以外的情況,例如「私鑰被盜」。接下來馬上就會介紹到,多了這個「私鑰被盜」的假設將會大大改變 Recovery 設計,或甚至在最後我們會發現:沒有一個 Recovery 機制能同時應付「私鑰遺失」、「私鑰被盜」與「惡意 Guardian」的情況。接下來,讓我們先討論「Owner 可能是惡意的」的情況,再一步一步揭曉「私鑰遺失」、「私鑰被盜」與「惡意 Guardian」這三個假設對 Recovery 設計的影響。

📖 Recap:如果假設 Guardian 可能是惡意的,那可以為 resetOwner 操作加上時間鎖。但記得加上時間鎖並不代表能免除對 Guardian 的信任。

如果我們假設 Owner 可能是惡意的

你可能會覺得奇怪,為什麼會假設 Owner(基本上就是使用者自己)可能是惡意的?這是當我們假設 Owner 的私鑰可能會被盜所需考慮的情況。因為我們賦予 Owner updateGuardians 的權力,讓 Owner 可以更新 Guardian 名單,所以如果 Owner 私鑰可能被盜,那就會導致攻擊者拿到 Owner 私鑰後直接把 Guardian 名單換掉,接著再換掉 Owner,如此使用者就等於失去錢包控制權了。即便使用者設定了再多 Guardian、用了再複雜的 Recovery 機制都毫無用處 – Owner 私鑰變成安全的破口,只要一被盜就等於失去錢包控制權。

如果 Owner 私鑰可能被盜,那攻擊者就有機會透過換掉 Guardian 再換掉 Owner 的方式拿走錢包控制權
如果 Owner 私鑰可能被盜,那攻擊者就有機會透過換掉 Guardian 再換掉 Owner 的方式拿走錢包控制權

如果假設 Owner 私鑰可能被盜,那合約錢包的 Recovery 機制就必須要加入額外的保護機制來處理 Owner 私鑰被盜的情況。

因此 Owner 的 updateGuardians 操作會加上時間鎖,且可以由 Owner 自己取消。Owner 可以自己取消的原因是因為私鑰被盜不代表失去私鑰,只是代表攻擊者和使用者同時都能使用同一把私鑰,因此使用者還是能透過 Owner 私鑰去取消攻擊者發起的 updateGuardians,取消後就是透過 Guardian 執行 resetOwner 讓攻擊者手上的私鑰失去效用。

註:但相反地,攻擊者也可以取消使用者發起的 updateGuardians,此時只能仰賴 resetOwner發揮作用,否則就會陷入僵局,例如 Guardian 消失不見或換了一把私鑰,使用者透過 updateGuardians 去更新 Guardian 名單,但接著就被攻擊者取消。

Owner 可以直接取消攻擊者發起的 updateGuardians
Owner 可以直接取消攻擊者發起的 updateGuardians
但攻擊者也可以取消使用者發起的 updateGuardians
但攻擊者也可以取消使用者發起的 updateGuardians

📖 Recap:如果假設 Owner 私鑰可能被盜,那 updateGuardians 操作就需要加上時間鎖,並且是由 Owner 可以來自己取消 updateGuardians,取消之後再透過 resetOwner 換掉私鑰,讓攻擊者手上的私鑰失去效用。

而因為假設 Owner 私鑰可能被盜,所以 resetOwner 的設計也需要改變。以下分別以 Guardian 不會是惡意及可能是惡意兩種情況做討論。

如果 Guardian 不會是惡意的

因為 Owner 私鑰可能被盜,所以 Guardian 的 resetOwner 操作不能設置時間鎖,因為如果有時間鎖的話,攻擊者就可以每一次都在時間鎖結束前取消 resetOwner,導致 Recovery 機制永遠卡住。這時如果假設 Guardian 是可信的,resetOwner 就可以直接讓 Guardian 完成,也不需時間鎖。

註:如果 Guardian 不會是惡意的,updateGuardians 操作也可以讓 Guardian 幫忙取消。

如果 Guardian 不會是惡意的,它和 Owner 都可以取消 updateGuardians,然後它再 resetOwner 使攻擊者手上的私鑰失去效用
如果 Guardian 不會是惡意的,它和 Owner 都可以取消 updateGuardians,然後它再 resetOwner 使攻擊者手上的私鑰失去效用

📖 Recap:如果假設 Owner 私鑰可能被盜但 Guardian 不會是惡意的,那 resetOwner 就不需要時間鎖,直接由 Guardian 完成。另外 Guardian 也可以幫忙取消 updateGuardians

如果 Guardian 可能是惡意的

如果 Guardian 可能是惡意的,這樣就不行授權 Guardian 可以直接完成 resetOwner。那要把時間鎖加回去嗎?如同上一段提到,因為 Owner 私鑰有可能被盜所以不能讓 Owner 有完全的權力來取消 resetOwner,如果我們要求 Owner 和 Guardian 一起同意才能取消時間鎖呢?這雖然可以防止攻擊者有權力直接取消,但如果 Guardian 是惡意的,那它肯定不會同意取消,等於 resetOwner 一定會成功,導致時間鎖形同虛設。因此時間鎖不適用在私鑰可能被盜與 Guardian 可能是惡意的假設前提下。

所以我們不用時間鎖,而是改成調整 resetOwner 的門檻:要求 resetOwner 要由 Owner 及 Guardian 一起同意才能執行。當 Owner 私鑰被盜,使用者會和 Guardian 一起執行 resetOwner;當 Guardian 是惡意的,Owner 會用 updateGuardians 換掉 Guardian。

如果 resetOwner 加上時間鎖且要 Owner + Guardian 才能取消:如果 Guardian 是好人,那攻擊者無法取消 resetOwner,只能被換掉 ✅
如果 resetOwner 加上時間鎖且要 Owner + Guardian 才能取消:如果 Guardian 是好人,那攻擊者無法取消 resetOwner,只能被換掉 ✅
如果 resetOwner 加上時間鎖且要 Owner + Guardian 才能取消:但如果是惡意的 Guardian,那它也不會同意 Owner 取消,導致 resetOwner 一定會成功 😱❌
如果 resetOwner 加上時間鎖且要 Owner + Guardian 才能取消:但如果是惡意的 Guardian,那它也不會同意 Owner 取消,導致 resetOwner 一定會成功 😱❌
不用時間鎖,而是有 Owner 和 Guardian 一起才能 resetOwner:單獨的攻擊者或惡意 Guardian 都沒辦法 resetOwner
不用時間鎖,而是有 Owner 和 Guardian 一起才能 resetOwner:單獨的攻擊者或惡意 Guardian 都沒辦法 resetOwner

如此 私鑰被盜 或是 惡意 Guardian 都沒辦法執行 resetOwner,但如果 同時發生 Owner 私鑰被盜和 Guardian 是惡意的,那還是會被攻擊者拿走控制權。

如果 Owner 私鑰被盜、Guardian 又是惡意的那仍然會被拿走錢包控制權
如果 Owner 私鑰被盜、Guardian 又是惡意的那仍然會被拿走錢包控制權

📖 Recap:如果假設 Owner 私鑰可能被盜且 Guardian 也有可能是惡意的,那 resetOwner 就不能加上時間鎖,而是要改成要求 Owner 和 Guardian 一起同意才能 resetOwner。如此 私鑰被盜 或是 惡意 Guardian 都沒辦法執行 resetOwner,但如果 同時發生 Owner 私鑰被盜和 Guardian 是惡意的,那還是會被攻擊者拿走控制權。

而且要注意的是:因為要 Owner 及 Guardian 一起同意,這表示 Owner 的私鑰是不能遺失的!這裡就是前面提到的「為什麼會需要考慮私鑰不會遺失的情況」,儘管私鑰不會遺失這種假設非常少見,但如果沒有注意到「私鑰遺失」、「私鑰被盜」與「惡意 Guardian」這些假設彼此之間衝突所產生的陷阱,就會設計出複雜但不安全的 Recovery 機制。

如果使用者遺失 Owner 私鑰,那就沒救了
如果使用者遺失 Owner 私鑰,那就沒救了

📖 Recap:如果 resetOwner 執行門檻要 Owner 及 Guardian 一起同意,那 Owner 的私鑰就不能遺失!如果 resetOwner 使用時間鎖允許 Owner 在時間鎖結束前取消,那 Owner 的私鑰就不能被盜!沒有 Recovery 機制可以同時假設私鑰會遺失、私鑰會被盜與惡意 Guardian。

沒有完美的 Recovery 機制

每個設計或機制都有它的極限,不同安全假設的 Recovery 機制也有各自的極限。就像假設私鑰會遺失的設計裡就無法不相信第三方的角色(Guardian),因為合約無法知道你的私鑰是否遺失,你一定會需要第三方的協助。

如果你不想完全相信 Guardian,你可以加入時間鎖來反制惡意 Guardian 並透過 updateGuardians 來換掉惡意的 Guardian。

如果在惡意 Guardian 的假設之上,又要再多假設 Owner 私鑰可能被盜,那 Recovery 機制又會變得更複雜:(1) Owner 的 updateGuardians 操作要加上時間鎖;(2) Guardian 的 resetOwner 操作要由 Owner 及 Guardian 一起同意,而且 Owner 不能遺失私鑰!

但再多、再複雜的機制都永遠無法同時應付 Owner 私鑰遺失Owner 私鑰被盜惡意 Guardian 這三種假設,這個就是 Recovery 機制的極限。在知道 Recovery 機制的極限後,剩下的就是按照需求並從這三種假設中選擇(最多)兩種,並按此假設去實作。詳細介紹可以參考後面的附錄。


總結與重點

  • 合約錢包的 Recovery 機制中有 Owner 及 Guardian 兩種角色,各自可以執行 resetOwnerupdateGuardians 兩個操作。在合約錢包的 Recovery 機制中,Owner 和 Guardian 都是和合約互動,而不是和彼此互動

  • 接著端看對 Guardian 及 Owner 兩個角色的信任的假設,會改變 Recovery 機制的設計。如果 Guardian 不可信,那就要在 resetOwner 操作加上時間鎖,讓 Owner 有時間可以反應並取消

  • 但請記得時間鎖並不是真的能移除對 Guardian 的信任,只要假設私鑰可能會遺失,就會需要賦予 Guardian 完全權力去執行 resetOwner

  • 如果 Owner 不可信,那 updateGuardians 操作也需要加上時間鎖,並讓 Owner 可以自己取消。而 resetOwner 也會因為 Owner 不可信而必須改變設計

  • 如果 Owner 不可信但 Guardian 可信,那 resetOwner 就不能加上時間鎖,而且 Guardian 也可以取消 updateGuardians

  • 如果 Owner 和 Guardian 都不可信(但假設不會同時發生私鑰被盜與惡意 Guardian),那 resetOwner 就不能用時間鎖,而是改成要 Owner 和 Guardian 都同意才能執行。如此可以防止 私鑰被盜 或是 惡意 Guardian 的情況,但如果 同時發生 Owner 私鑰被盜和 Guardian 是惡意的,那還是會被攻擊者拿走控制權

  • 不同的 Recovery 設計都有其極限,但沒有一個 Recovery 設計可以同時應付 Owner 私鑰遺失Owner 私鑰被盜惡意 Guardian 這三種假設。在這個極限之下,我們按照需求並從這三種假設中去實作我們的 Recovery 機制


附錄

有沒有什麼辦法能夠免除對 Guardian 的信任?

讓我們思考看看,以下幾種方法是否能免除對 Guardian 的信任:

方法 1:Guardian 不能被授權來 resetOwner

但如此除了 Owner 之外就沒有人可以來 resetOwner 了,而 Owner 自己都遺失私鑰了自然是不可能可以更新 Owner 地址,因此這個方法不可行。

方法 2:Guardian 執行 resetOwner 要經過使用者同意

同樣地,Owner 都遺失私鑰了所以沒辦法簽名同意。那如果請 Owner 預先產生另一把私鑰用來簽名同意呢?那其實等同於使用者直接將另一把私鑰設為 Guardian,基本上就等於是使用者自己在做備份。但不管 Guardian 是第三方或是使用者自己,都改變不了 Guardian 要有完全的權力可以 resetOwner 的事實。

Guardian 可以是第三方或是使用者的另一把私鑰,但無論如何 Guardian 都要有完全權力可以 resetOwner
Guardian 可以是第三方或是使用者的另一把私鑰,但無論如何 Guardian 都要有完全權力可以 resetOwner

因此我們得到結論:如果私鑰可能會遺失,那一定得信任 Guardian;如果私鑰不會遺失,那就不需信任 Guardian,也就是不需給 Guardian 完全的權利能 resetOwner

不同假設所組合出來的設計

不同假設所組合出來的設計
不同假設所組合出來的設計

1. 假設 Owner 私鑰不會遺失

那就可以應付 Owner 私鑰被盜惡意 Guardian,但這樣的假設實在不太實際

註:但沒辦法應付 Owner 私鑰被盜 與 惡意 Guardian 同時發生

如果私鑰被盜,使用者可以取消攻擊者發起的 updateGuardians,並和 Guardian 一起 resetOwner
如果私鑰被盜,使用者可以取消攻擊者發起的 updateGuardians,並和 Guardian 一起 resetOwner
如果 Guardian 是惡意的,使用者可以換掉惡意的 Guardian
如果 Guardian 是惡意的,使用者可以換掉惡意的 Guardian

2. 假設 Owner 私鑰不會被盜

那就可以應付 Owner 私鑰遺失惡意 Guardian(能透過時間鎖反制惡意 Guardian,但並不能真的移除對 Guardian 的信任)

註:但沒辦法應付 Owner 私鑰遺失 與 惡意 Guardian 同時發生

如果私鑰遺失,Guardian 可以 resetOwner 更換 Owner 私鑰
如果私鑰遺失,Guardian 可以 resetOwner 更換 Owner 私鑰
如果是惡意 Guardian,Owner 可以取消 resetOwner 並換掉 Guardian
如果是惡意 Guardian,Owner 可以取消 resetOwner 並換掉 Guardian

3. 假設 Guardian 是可信的

那就可以應付 Owner 私鑰遺失Owner 私鑰被盜

Guardian 可以直接進行 resetOwner 以及取消 updateGuardians (使用者也可以取消 updateGuardians)
Guardian 可以直接進行 resetOwner 以及取消 updateGuardians (使用者也可以取消 updateGuardians)

4. 假設 Owner 私鑰不會被盜且 Guardian 是可信的

那就更簡單了,resetOwnerupdateGuardians 都不需加上時間鎖

Guardian 可以直接 resetOwner,Owner 可以直接 updateGuardians
Guardian 可以直接 resetOwner,Owner 可以直接 updateGuardians
Subscribe to imToken Labs
Receive the latest updates directly to your inbox.
Mint this entry as an NFT to add it to your collection.
Verification
This entry has been permanently stored onchain and signed by its creator.