時間扭曲攻擊

作者:BitMEX Research

來源:https://blog.bitmex.com/the-timewarp-attack/

摘要:我們分析了比特幣的一種安全漏洞,稱作 “時間扭曲攻擊”。這種攻擊允許佔據算力多數的敵意礦工操縱區塊時間戳,從而可以任意調降出塊難度、以至於幾秒鐘就可以挖出一個區塊。這一弱點首次被發現是在大約 2011 年,可以通過 “共識清理軟分叉” 來修復。我們還探討了所提議的修復措施的部分細節。

clock-1024x919

2025 年 3 月 26 日,比特幣開發者 Antoine Poinsot 公開了一個新的比特幣升級提議。該軟分叉提議叫做 “共識清理(The Great Consensus Cleanup)”。這一升級修復了多項比特幣協議中存在已久的 bug 和漏洞。其中一個是 “重合交易” 問題,我們在近期一篇文章中已經討論了。另一個可以修復的 bug,也是更加嚴重的一個,叫做 “時間扭曲攻擊”,就是我們這篇文章的主題。

比特幣的區塊時間戳保護規則

在我們討論時間扭曲攻擊之前,不妨先回顧以下當前的時間戳操縱保護規則

  • 過往時間中值(MPT)規則:一個區塊的時間戳必須大於過去 11 個區塊的時間戳的中值。
  • 未來區塊時間規則:根據 MAX_FUTURE_BLOCK_TIME 常量,區塊的時間戳不能超過本地時鐘 2 小時以上,這個 “本地時鐘” 是來自節點的對等節點的當下時間的中值。(譯者注:此一實現的細節似乎已經更改。)另一個保護裝置是,來自對等節點的時間,與節點的系統時鐘的時間,相差不能超過 90 分鐘。

MTP 規則是為了確保區塊的時間戳不會倒撥到許久以前;未來區塊時間規則用於防止時間戳撥到太遙遠的未來。請注意,類似於未來區塊時間規則的做法不能用來防止區塊時間戳倒撥,因為這會影響初始化區塊鏈同步。時間扭曲攻擊涉及到假的時間戳,以及倒撥到許久以前的時間戳。

中本聰的 “差一錯誤”

在比特幣中,一個難度調整週期的長度是 2016 個區塊;配合上 10 分鐘的出塊時間目標,意味著一個週期大約長兩個星期。為了計算挖礦難度的調整量,協議會計算最近一個難度調整窗口的第一個區塊和最後一個時間戳的差值。在由 2016 個區塊構成的窗口中,包含了區塊間 的 2015 段出塊間隔(沒錯,就是 2016 減 1)因此,合理的挖礦目標時間應該是 60 秒 * 10 分鐘 * 2015 個間隔,也就是 120 9000 秒。然而,比特幣協議使用的間隔數量是 2016,使目標時間定義成了 120 9600 秒。這就是一個差一錯誤。這是一個很容易犯的錯誤,中本聰似乎搞混了區塊數量與區塊間隔的數量。

中本聰的代碼

const unsigned int nTargetTimespan = 14 * 24 * 60 * 60; // two weeks

- 來源:https://sourceforge.net/p/bitcoin/code/1/tree//trunk/main.cpp%23l687 -

這個錯誤讓目標時間比應該的長了 0.05%。因此,比特幣的目標出塊間隔並不真的是 10 分鐘,而是 10 分鐘又 0.3 秒。這個 bug 並不那麼要緊,因為自比特幣啟動一來,出塊間隔平均值是 9 分鐘又 36 秒,遠遠低於 10 分鐘。這是因為自 2009 年以來,平均來說挖礦算力一直在增長。這也是為什麼最近一次比特幣貨幣增發減半發生在 2024 年 4 月,而不是預期的 2025 年 1 月。我們趕在了日程表前面。不管怎麼說,中本聰犯的這個 0.3 秒的錯誤在宏觀層面上是無關緊要的。也許許多年以後,當比特幣的價格和哈希率都停止增長的時候,這個 bug 會讓我們回到預想的貨幣發行日程表。

d-1536x668

雖然 0.3 秒的 bug 自身並不算什麼,一個相關的問題就變成了可以說嚴重的漏洞。難度調整量的計算基於每一個長為 2016 個區塊的窗口中的第一個區塊和最後一個區塊。這也是不對的,從我們的視角看,合理的週期應該是本窗口最後一個區塊與上一個窗口的最後一個區塊的差值。這顯然是計算難度調整週期長度的最符合邏輯的方式,關鍵之處是它會讓時間區域與不同的難度調整窗口重疊。如果一開始就是這樣做的,那麼 2016 也會成為用於計算目標出塊時間的正確間隔數量。

也許,中本聰犯下這個錯誤的理由在於,他必須考慮第一個難度調整窗口 —— 沒有更早的難度調整窗口,也就無所謂上一個窗口的最後一個區塊。

時間扭曲攻擊

對比特幣的時間扭曲攻擊第一次被發現是在 2011 年,也利用了中本聰在難度計算中的錯誤。為了理解攻擊,我們假設挖礦是 100% 中心化的,所以礦工可以設置協議所允許的任意時間戳。在攻擊中,對挖出的所有區塊,礦工都將時間戳設為比上一個區塊多一秒,因此區塊鏈的時間是向前的,也滿足了 MTP 規則。要想時間戳挪動得儘可能慢,礦工可以為 6 個一組區塊使用完全相同的時間戳,然後為下一組使用增加了一秒的時間戳,以此類推。這意味著每挖出 6 個區塊,最新區塊的時間戳只會正著往前撥動一秒。

這種攻擊意味著,區塊鏈最新區塊的時間戳會逐漸落後於真實時間,而且,由於時間戳差值太小,難度就會上升,讓挖礦變得越來越困難。但是,我們繼續給攻擊加料 —— 在每一個難度調整窗口的最後一個區塊,礦工將時間戳設為真實世界的時間數值。到了下一個區塊,也就是下一個難度調整窗口的第一個區塊,礦工又將時間倒撥,撥到僅僅比上一個難度窗口的倒數第二個區塊多一秒。這依然滿足 MTP 規則,因為一個異類並不影響過往 11 個區塊的時間戳中值。

在發動這樣的攻擊的時候,第一個窗口的難度並不會受影響。然而,在攻擊開始的第二個難度調整窗口之後,難度就會下降。然後礦工就可以用極快的速度創建區塊,也許能創造大量的比特幣,甚至可以全部賣出獲利。

精心設計的圖解

因為一個難度調整窗口是 2016 個區塊,所以很難在一張圖中演示這樣的攻擊。因此,我們設計瞭如下場景來解釋時間扭曲攻擊。

  • 每一次難度調整窗口只有 5 個區塊
  • 目標出塊間隔是 10 分鐘
  • MTP 規則只考慮過去 3 個區塊
  • 每一個區塊的時間戳都只多 1 分鐘,除了每個窗口的最後一個區塊,它會使用真實時間

c-1536x938

- 圖解時間扭曲攻擊 -

如上圖所示,有兩種線條:

  1. 紅色曲線表示真實時間,在每一個難度調整週期的最後一個區塊,與表示區塊時間戳的藍色直方線相交。這條曲線會變得越來越平緩,因為礦工的出塊速度(隨著難度降低而)越來越快。
  2. 藍色的直方線,表示被操縱的時間戳。

時間扭曲攻擊的計算

下圖展示了在最極端的情況下,礦工使用時間扭曲攻擊可以讓挖礦難度多麼快速地下降。

難度調整窗口數量難度下降幅度累計難度降幅出塊間隔(分鐘)單窗口時長(天)累計時長(天)
1NoneNone10.0014.0014.00
22.0x2.0x10.0014.0028.00
32.5x5.0x5.007.0035.00
42.7x13.5x2.002.8037.80
52.8x37.4x0.741.0438.84
62.8x104.7x0.270.3739.21
72.8x294.1x0.100.1339.35
82.8x826.8x0.030.0539.39
92.8x2325.6x0.010.0239.41
102.8x6541.3x0.000.0139.42
112.8x18398.0x0.000.0039.42

注意:協議所允許的單窗口最大難度調整幅度是 4 倍,但上圖並沒有達到。

單週期的難度調整降幅只稍微高於 2.8 倍。這是因為隨著每一個週期的時長變得越來越短,難度下降得也越來越慢。

在上表的第 11 個窗口,也就是攻擊發動後的第 39 天,一秒鐘可以生產超過 6 個區塊,準確來說是 10.9 個。這時候,分配給區塊的時間戳的作用就發生了變化。根據 MTP 規則,每 6 個區塊,時間戳就必須正著往前撥,最小的增量是 1 秒鐘。因此,這時候,基於我們理解,時間戳的移動會快於真實時間的移動,區塊鏈時鐘會開始趨向真實值,但依然會落在真實時間的後面。除此之外,攻擊可以持續,直到難度降低到不能再低(到達允許的最小值)為止。

攻擊的顯著性

雖然理論上這種攻擊是毀滅性的,但真要發動它也面臨一些困難。執行攻擊可能需要佔據大多數算力。只要有誠實礦工發佈誠實的時間戳,攻擊的難度就上身。MTP 規則和來自誠實礦工的時間戳可能會限制惡意礦工的時間戳倒撥的程度。此外,只要誠實礦工生產出了任何一個難度調整窗口的第一個區塊,攻擊在該窗口就不會生效(會暫停)。另一個會讓攻擊難度上升的緩解因素是,這樣的攻擊對每一個人都是可見的。時間戳對所有人都是可見的;而在難度真的下降之前,需要操縱時間戳長達 4 個星期;我們也許能夠在此期間推出一次緊急軟分叉來阻止它。

解決方案

修復這個漏洞不難,雖然可能需要一次軟分叉協議變更。改變難度調整算法、計算另一個 2016 個出塊間隔的區塊時間戳差值、完全修復差一錯誤,可以直接修復問題,但是非常複雜,可能需要硬分叉。另一種修復方法是摒棄 MTP 規則、要求每一個區塊的時間戳都必須大於上一個區塊的,雖然這可能意味著時間戳會跑到真實時間前面去,而且也意味著使用自己的操作系統時鐘的礦工會吃虧,因為其他礦工都把時鐘撥快了幾秒鐘(從而他的時間戳就成了無效時間戳)。

幸運的是,還有一種非常簡單的解決方案。為了防止時間戳攻擊,我們只需讓難度調整窗口的第一個區塊的時間戳不能比上一個窗口的最後一個區塊小太多。這個限度的具體數值(分鐘數)一直在被討論,人們的提議從 10 分鐘到 2 小時都有。從緩解時間扭曲攻擊的角度看,不論哪個似乎都可以。

Poinsot 的共識清理提議的當前版本決定使用 “2 小時”。2 小時只是一個難度調整窗口目標時間的大約 0.6%,因此,操縱難度調降的能力會大大受限。我們已經總結了關於寬限期長度的討論:

10 分鐘

支持意見:

  • 此數值有非常吸引人的特性:它剛好對沖了差一錯誤的影響。如果有人發動攻擊,效果會剛好被中本聰的錯誤抵消。

反對意見:

  • 如果一個礦工使用真實時間來設定時間戳,有變成無效區塊的額外風險。
  • 這個規則是更為巨大的協議變更,可能在常規情形中比 MTP 更為嚴格,增加額外的複雜性。

2 小時

支持意見:

  • 這個寬限期足夠長,儘可能降低了意外開採出無效區塊的風險。
  • 這是 Fabian Jahr 在測試這一提議時為 testnet4 選擇的數值。
  • 這個數值匹配了未來區塊時間戳規則,因此總是允許礦工在一個區塊內糾正最大允許未來時間錯誤。
  • 相比於當前的規則集,這是一種更加保守的變更,可能比常規情況下的 MTP 規則更輕鬆

反對意見:

  • 這依然允許發動攻擊的礦工在每個窗口中將難度調降大約 0.6%;不過,這會是一次性的變更,不能倍乘。

(完)

來源
免責聲明:以上內容僅為作者觀點,不代表Followin的任何立場,不構成與Followin相關的任何投資建議。
喜歡
收藏
評論