區塊鏈安全—詳談共識攻擊(一)
本篇詳細講述了區塊鏈中非常重要的“共識”演算法及其安全性,由於文章內根據不同應用環境講述了不同的共識演算法及其安全,所以涉及到的內容相對比較豐富。
前言部分
區塊鏈作為一種去中心化的分散式公共資料庫,其並沒有中央管理機構進行管理工作,而是通過分散式節點共同利用密碼學協議共同維護。而各個節點在維護整個系統的的時候要通過底層的共識協議來保證賬本的一致性。而在區塊鏈中我們又可以分為公有鏈和許可鏈,而由於實際的用途不同,這些共識演算法也有所不同。而不同的共識演算法所涉及的安全性又有所區別。
一、共識安全模型分析
我們知道,區塊鏈的本質是一個分散式系統。而對於分散式系統來說,不同的共識模型在不同的環境下能夠容忍的錯誤型別與數理也是不同的。所以我們可以由分散式系統共識的評判標準引申出對區塊鏈的安全性定義。
1、 同步模型
顧名思義,同步模型要求傳送訊息方與接收方直接類似於面對面應答。即其延遲時間 Δt 是確定的,並且演算法的執行時間也是確定的。然而同步模型在現實世界中並不存在,在分散式系統中延時是肯定存在的,所以延遲時間就並不確定。所以這種模型也就只是一種假設,如果此假設被應用於實際,那麼我們依據此模型而進行的進一步研究的正確性將無法被保證。從另一個角度想,如果在同步模型的假設下,依然沒有演算法可以解決某個問題,那麼在非同步模型下,失去了可以預測的時間,這個問題更加沒辦法解決。
2 、非同步模型
非同步模型中,訊息的延時時間 Δt 並不是確定的,可以是任意長的時間。在非同步模型中,程式執行到某個語句可能會因為訊息的等待而進入阻塞狀態,所以其執行時間是非常不確定的。所以使用此演算法也有一定的弊端,例如我們無法判斷節點訊息是由於延時還是由於節點已經宕機。然而這種演算法可以保證程式的安全性,但是對系統的靈活性並不友好。
3、 半同步/半非同步模型
為了將上述兩種模型的優點整合起來,我們基於時間模型上設計了半同步 / 半非同步模型。在這個模型的架構中,我們會設計一個最長超時限制 tmax。倘若時間超過此tmax而訊息接收方依然沒有收到訊息,那麼我們就可以大膽的假設這個節點已經宕機,並不在等待這個節點訊息。
二、Pow共識演算法
目前的數字貨幣大多使用工作量證明機制來進行維護賬本。工作量證明機制是由 Nakamoto 匿名提出, 將其用來作為比特幣系統的共識機制,其主要思想是使用計算能力尋找特定的數字來使區塊滿足要求。
因為區塊鏈系統是以去中心化為其特性,那麼我們的每個節點都需要一份本地的完整賬本來對整個區塊鏈網路的資訊進行把控。並且在更新賬本的時候要依賴其中某個節點的幫助,但是每個節點卻不能同時記賬,因為節點處於不同的環境,接收到不同的資訊,如果同時記賬的話,必然會導致賬本的不一致,造成混亂。因此,需要有共識來達成哪個節點有權記賬。比特幣區塊鏈通過競爭記賬的方式解決去中心化的記賬系統的一致性問題, 即以每個節點的計算能力即“算力”來競爭記賬權的機制。
在比特幣系統中,大約每10分鐘進行一輪算力競賽,競賽的勝利者,就獲得一次記賬的權力,並向其他節點同步新增賬本資訊。然而,在一個去中心化的系統中,誰有權判定競爭的結果呢?比特幣系統是通過一個稱為“工作量證明”(Proof of Work,PoW)的機制完成的。
而這個簡單來說,Pow就是一種所有節點均遵循的共識,共識要求每個節點進行一定難度的雜湊計算工作,正如我們的工作制度一樣。工作端需要做一定難度的工作得出一個結果,驗證方卻很容易通過結果來檢查工作端是不是做了相應的工作。
舉個例子,假設我們給定字串“blockchain”,我們在此字串後面連線nonce隨機數(32位)並對連線後的字串進行SHA256雜湊運算,如果得到的雜湊結果(以十六進位制的形式表示)是以若干個0開頭的,則驗證通過。為了達到這個工作量證明的目標,我們需要不停地遞增nonce值,對得到的新字串進行SHA256雜湊運算。
1 blockchain1 → 4bfb943cba9fb9926df93f33c17d64b378d56714e8a29c6ba8bdc9690cea8e27 2 blockchain2 → 01181212a283e760929f6b1628d903127c65e6fb5a9ad7fe94b790e699269221 …… 3 blockchain515 → 0074448bea8027bebd6333d3aa12fd11641e051911c5bab661a9b849b83958a7…… 4 blockchain2688 → 0009b257eb8cf9eba179ab2be74d446fa1c59f0adfa8814260f52ae0016dd50f…… 5 blockchain48851: 00000b3d96b4db1a976d3a69829aabef8bafa35ab5871e084211a16d3a4f385c…… 6 blockchain6200969: 000000db7fa334aef754b51792cff6c880cd286c5f490d5cf73f658d9576d424
按照這個規則,需要經過2688次計算才能找到前3位均為0的雜湊值,而要找到前6位均為0的雜湊值,則需進行620969次計算。
所以簡單來說,系統通過激勵措施鼓勵使用者通過維護區塊鏈系統來獲取利益。參與共識過程的使用者收集新產生的交易記錄構造區塊,嘗試修改區塊中 Nonce 的值,直到該區 塊的雜湊值小於特定難度的雜湊值,便可以對外廣播 區塊。該區塊得到其他使用者驗證和認可,成功新增到主鏈之後,使用者就可以獲得相應的獎勵。
在這裡我們將一個區塊表示為包含三元組的資料 包 B = (h',tx,nonce),其中h' 是前一個區塊的雜湊, tx 是區塊中所包含的交易記錄,nonce 是一個 32 位元的整數
。為了達到某個共識,區塊鏈系統會針對當前系統中使用者量或者整體計算量的情況進行難度值D的設定。而D 定義了當前整個區塊雜湊值需要有多少位前導 0,前導 0 數量越多,難度越大。由於 nonce 改變任意一個位元都會使整個區塊的雜湊 H(B)完全改變,所以沒有方法可以 預測哪種形式的 nonce 可以符合要求。因此為了達到區塊的要求,節點需要用其計算資源嘗試大量可能的 nonce 值使得 H( B) < D。
系統輸入:tx、nonce、D Pow過程: 1:nonce = 1(初值) 2:while(H(nonce,tx,h') > = D): 3: nonce++ 4:Broadcast( < nonce,tx,h' > )//廣播計算的值 5:end
既然Pow可以解決這麼多問題,那麼其存在的安全隱患是什麼呢?我們看下面的內容。
三、Pow攻擊詳解
1 、雙花攻擊
簡單來說,雙花攻擊就是指同一個貨幣被花費了多次。在區塊鏈網路中,每個使用者的每一次交易都可以對應一個網路請求。而區塊鏈整個系統會進行對此請求的驗證。其中包括檢查其資產的有效性、是否已經使用已花費的資產來進行交易。經過全網節點的檢驗後,廣播這個成功驗證的賬本。
舉個例子來說,小明拿著編號為123456的一百元去購買《區塊鏈安全》這本書,之後又拿這個123456編號的錢同樣購買了《人工智慧》這本書。此時小明就使用同樣的一份錢購買了兩次商品。
那傳統的方面是如何解決這種情況的呢?
防止雙花可以從交易和貨幣本身來控制,首先從交易上,例如我們都是以刷卡交易,卡上的資產都是在銀行作為第三方參與者手中,我們將100元從小明的手裡轉到了商家手裡,假如這個過程中存在延時,那麼小明幾乎是同時在兩個地方消費了100元,銀行也就同時收到了關於這筆錢的兩次消費。然而銀行會按順序一筆一筆處理,第一筆處理完之後,小明已經沒錢了,第二筆自然就失敗。
那區塊鏈系統是如何解決這個問題的呢?
1 、首先,假設我們的比特幣擁有者A想要從B處購買一本書,他會像全網廣播:A向B支付一個bitcoin去購買。
在廣播這個資訊的時候,A會將這個資訊使用雜湊函式加密並使用A自己的私有進行簽名。
接收到這條資訊的B和其他使用者先用同樣的Hash函式對明文資訊生成摘要,再用A的公鑰對加密資訊進行解密,如果解密得到的摘要與明文生成的摘要相同,便認為資訊確實是A發出的,且沒有經過篡改。
A的公鑰和Hash是公開的,私鑰則無法算出,只有A知道,這樣就既保證了交易的達成,又保證了A的資訊無法被竊取。
2 、假設黑客想對這筆交易進行攻擊,那麼他需要獲得區塊記賬權。然而是否擁有記賬權取決於黑客是否能算出符合要求的雜湊值。而這一步是困難的,代價也是巨大的,所以基於Pow的共識機制也就保證了大概率的資料安全。
3、 由於區塊鏈分散式系統的特性,其在交易的時候存在延時是不可避免的,所以交易並不是立刻執行。所以交易確認的時間要長很多,使得這種詐騙有可能實現,這就是比特幣的double spending雙重花費問題,簡稱“雙花”。
對於雙花問題,說區塊鏈網路是如何應對的呢?
-
每一筆交易都會有記錄,他會提前確認這個比特幣的狀態,如果它已經被標記為劃掉,那麼交易會被拒絕。
-
如果在此次交易被確認前先發起一筆交易,也就是這個時間段的交易還未被記賬成區塊block時,進行矛盾的第二筆交易,那麼在記賬時這些交易會被礦工拒絕。
2 、51%攻擊
然而在Pow體系下,系統同時允許存在多條分叉鏈,而每一條鏈均可以宣告自己的正確的。但是在區塊鏈的設計理念中有一個最長有效原理:“不論在什麼時候,最長的鏈會被認為是擁有最多工作的主鏈。”比特幣目前需要12個區塊的確認時間才可以保證交易的不可篡改。
下面我們模擬一下具體的過程:
如果攻擊者者把第一筆交易向一半網路進行廣播,把第二筆交易向另一半網路廣播,然後兩邊正好有兩個礦工幾乎同時取得記賬權,把各自記的區塊釋出給大家的話,網路是不是會混亂呢?
即在原來的賬本中出現了分叉的情況。
根據我們上面提到的,假設下一個礦工選擇在A基礎上繼續記賬的話,A分支就會比B分支更長,根據區塊鏈的規則,最長的分支會被認可,短的分支會被放棄,賬本還是會迴歸為一個,交易也只有一筆有效,而B鏈分支會被捨棄:
加入作惡人在A分支確認並拿到商品後自己立刻變為礦工,並爭取到連續兩次記賬的權利,在B分支上新增兩個區塊呢?:
於是B分支成為認可的分支,A被捨棄,A分支中的交易不再成立,但他已經拿到商品,詐騙成功。
我們發現這其實就是一種攻擊方法。但是我們有沒有想過上述攻擊成立的條件是B拿到了連續兩次記賬的權利。我們可以大致算一下:
假設詐騙者掌握了全網1%的計算能力,那麼他爭取到記賬權的概率就是1%,兩次就是10的負4次方。那還是存在一定概率進行攻擊的。
既然連續兩次的概率比較大,那麼我們就將次數增加。也就是等6個入鏈並被確認後再把交易對應的商品交付。
這樣概率也就幾乎為零了(在百分之1的算力情況下)。
下面我們就算個數,倘若我掌握了全網的51%的算力,那麼我成功記錄六個區塊的概率是多少呢?
即0.018,也就是說,幾乎100筆交易中我就有可能進行一次攻擊。那這樣的危害也就很大了。
3 、自私挖礦
在Pow機制中,除了上述通過“算力”這種大吃小的安全隱患外,還有一種通過小技巧進行的安全危害——“自私挖礦”。
誠實挖礦的策略如下: 其挖到區塊鏈後就對其進行全網廣播。而在自私挖礦的策略中,礦工維護兩個區塊鏈,其中一個鏈是公開的一個是私密的。一開始私密區塊鏈等於公開區塊鏈。在礦工挖到區塊之後,它並不將新挖的區塊加入公開鏈中,而是新增到本地的私密區塊鏈中,並不廣播給其他人。而我們可以想象到,加入我已經知道上一個區塊的值,我就可以先人一步進入下一個區塊的計算中。(如同我們考試的時候提前將第一天做出來,就可以快人一步做第二道題)。即使當前區塊被被人提前發了出來,我們也可以將自己挖出的區塊公佈到全網中。
而誠實礦工可能會在不知情的情況下選擇 “支援” 攻擊者所在分叉:即在攻擊者釋出的區塊後面繼續挖礦。這是如何出現的呢?當攻擊者的長鏈分叉資訊率先傳遞到某個誠實礦工那裡,這個誠實礦工會根據比特幣的共識機制,認可該分叉內區塊的合法性,並且選擇在該長鏈尾部繼續挖礦。這令攻擊者處在更為有利的位置上。事實上,出現這種情況,恰恰是由於比特幣網路資訊傳播存在時延所致。對於網路上的其他節點來說,這兩個區塊的高度是相同的,所以被其他節點承認的概率還有1/2,這樣自私礦工就有了相對於其他人的優勢。
然而自私挖礦策略僅對使用Pow共識有效果,對Pos等不適用。
四、Pos、DPos共識演算法
Pos演算法: 由於區塊鏈的分散式結構,所以區塊鏈的共識過程也就是我們所說的選擇一個leader的過程,並且有這個領導人來進行新的區塊的釋出工作,但是在設計共識的過程中我們也要避免單個使用者或者財團對賬本的長期控制。而根據我們上述的Pow機制,我們發現這種共識機制會浪費巨大的電力資源,並且存在了許多安全隱患,例如自私挖礦與雙花攻擊。
正是由於Pow中存在的不足情況,Pos孕育而生。PoS中文名為股權證明機制,它希望使用股權來代替或者部分代替計算資源來完成這個領導人選舉的過程。在股權證明機制的過程中,共識演算法根據參與共識過程每個人所持有股權比例來選擇下一個出塊的人。
這一種思想也是參考了我們生活中的經濟社會。即一個人擁有的股份數量越多,其獲得的股份以及紅利越多。這也使得區塊鏈在幣圈中更加貼近金融,有著通脹的情況產生。我們來看實際的協議是如何執行的。
例如 Peercoin,其協議在執行的過程中採用幣齡作為一個參考變數來影響下一個區塊的挖礦難度。在共識過程中,節點需要提交一份交易記錄來證明對區塊鏈資產的擁有權,並且擁有的區塊鏈資產越多,持有時間越長,挖礦就會越容易。演算法希望使用者對自己所擁有的資產進行證明,而這些資產可以影響礦工的挖礦難度。擁有的資產越多,就越有機會計算出符合條件的 nonce。因此其計算公式為:
success = <coins * age * target(難度值)>
而當proofHash < success的值時,挖礦成功。
系統輸入:tx、nonce、D Pos過程: 1:nonce = 1(初值) 2:coins←accountBalance 3:age←currentTime-lashTransactionTime //幣齡 4:while(H(nonce,tx,h') > = coins * age * D): 5: nonce++ 6:Broadcast( < nonce,tx,h' > )//廣播計算的值 7:end
雖然Pos演算法比起Pow有其獨特的優點用以避免計算資源的競爭,但是它仍會存在某些問題。比如使用者長時間擁有了全網的大量資產,那麼根據計算公式,他的計算難度就比其他節點小很多,這樣就會造成嚴重的“貧富不均”情況。不僅如此,Pos仍需要進行雜湊計算,所以仍然存在浪費計算資源的情況。
所以我們設計了第三種公式機制——DPos。
DPOS 是去中心化交易所 Bitshares 提出並使用的共識演算法。在Bitshares中存在三種類型的使用者:見證人(witnesses),代表(delegates)和工人(work- ers)。見證人如同礦工,通過處理交易和維護區塊鏈來獲得報酬。而代表可以發起更新請求,但是他們並沒有報酬。工人可以提出自己下一步的專案想法,如果此專案獲得了大部分人的投票支援,那麼他們會從中獲得收益。
DPos在共識期間分為“見證人選舉”和“見證人出塊”兩個過程。見證人對各個交易進行驗證簽名與時間。在網路中每個賬戶都可以為下一個見證人投票,而票數要根據區塊鏈的資產情況來分配。
見證人選舉過程如下:
只有擁有被選舉權的永久節點才能夠被選舉,最終只有前N名見證人可以被選舉出來。這N個人都要獲得50%以上的票數才能夠順利當選,除此之外,這個名單會按照固定的時間間隔進行重新選舉。
見證人出塊過程如下:
見證人每生產一個塊,都會獲得報酬,他們的薪酬水平由其獲得的投票決定。如果見證人沒有生產區塊,他們便沒有收入,並且還有可能被 投票失去見證人的身份。
見證人生產區塊時,每 2 s 生產一個區塊,如果見 證人沒有在規定的時間生產塊,如果超過了規定的時間,那麼當前見證人就會失去生產權利而轉交給下一個人。網路中所有的使用者均有責任監控區塊鏈生成的過程,並且同意需要選擇分叉最長的那個鏈進行追加。
五、確定性共識演算法攻擊
1、確定性演算法重放攻擊
傳統計算機術語中,重放攻擊(Replay Attacks)又稱重播攻擊、回放攻擊,是指攻擊者傳送一個目的主機已接收過的資料包,來達到欺騙系統的目的。重放攻擊在任何網路通過程中都可能發生,是計算機世界黑客常用的攻擊方式之一。
在區塊鏈技術中,重放攻擊是指“一條鏈上的交易在另一條鏈上也往往是合法的”。簡單來說,就是攻擊者“重放”他們在網路上竊聽到的訊息。
由於硬分叉的兩條鏈,它們的地址和私鑰生產的演算法相同,交易格式也完全相同,因此導致在其中一條鏈上的交易在另一條鏈上很可能是完全合法的。所以你在其中一條鏈上發起的交易,就可以到另一條鏈上去重新廣播,可能也會得到確認。這就是“重放攻擊”。而這種攻擊一旦發生,就會產生類似於雙花攻擊那樣的效果:同一筆錢轉給了同一個人兩次,就會導致在不需要付款人蔘與的情況下多一次支付。
那我們如何防止重放攻擊呢?
下面我們講解兩種方法去防止:
-
1 對於UTXO模型,我們需要對收到的交易檢查其Hash是否存在。
-
2 對於Balance模型,我們需要防止隨機數NONCE用以防止重放攻擊。
而在傳統的密碼學協議中,我們首先可以新增時間戳來防止重放攻擊:
DateTime current = DateTime.Now; // 每次訪問的時間 if (current >= _dt.Add(RefreshTime)) // 如果訪問的時間大於一個特定的時間戳,則需要更新儲存的時間 { _dt = current; // 生成新的nonce值 // ... }
在client每次訪問的時候,需要檢視這個時間是否過期了,如果過期了,需要重新記錄下當前的訪問的時間。
除此之外,我們可以使用挑戰相應機制,每次傳送挑戰並使用公鑰密碼去驗證對方身份,以杜絕中間人的破壞行為。
2、 權利壓迫攻擊
這種攻擊方法簡單來說,就是攻擊者在獲得記賬權的時候利用手中的部分權利實施一些操作讓系統的隨機數產生偏移用以增加自己下一次獲得記賬權力的可能性。
方式一:驗證者通過一些引數的組合找到一些特殊引數用以增加自己被選擇的可能性。
方式二:利用對當前區塊的控制力來影響下一個區塊。
例如:假設N+1個區塊的隨機性依賴於區塊N的簽名,那麼如果攻擊者在當前區塊中始終指向自己,那麼他將永遠獲得記賬權。
在解決這類問題時,我們可以採取如下手段:讓驗證者抵押自己的資產以避免作惡,並且避免使用那些容易被操控的資訊來產生隨機數。