大家好,我是張開翔。
上一篇分享了“信任區塊鏈時究竟在信任什麼?”(還沒看的童鞋,點選標題可直達),這次換個角度,漫步月之暗面,談談在區塊鏈系統和業務設計時,不信任什麼。
先講結論: 幾乎什麼都不能信!
建立Don't Trust,Just Verify的理念,才是通往區塊鏈世界的正確態度。
——By我隨口說的
1 不信任其他節點
區塊鏈節點和其他節點會建立P2P通訊,共同組成網路,傳遞區塊、交易、共識信令等各種資訊。其他節點可能是由不同的機構、不同的人持有,持有節點的人可能是善意,也可能是惡意。
即使在善意假設時,節點執行存活的健康度也會受運維水平和資源影響,比如處於一個不穩定的網路裡,會偶爾掛掉,會抽風亂髮訊息,或者硬碟滿等原因導致資料儲存失敗,以及出現其他可能的故障。
在惡意假設時,要預設其他節點可能會騙自己或傷害自己,比如傳遞過來錯誤的協議包,或者用詭異的指令尋找漏洞進行攻擊,或者發起高頻垃圾請求,頻繁連線然後斷開,又或者海量連線佔用資源等。
所以節點應該是把自己看成在黑暗叢林裡孤身求生存的獵人,必須有“獨立自主”、“自給自足”的態度,擺出“不相信其他任何節點”的姿勢保護自己。在節點准入時,需要採用證照技術來認證節點身份;在連線控制上,拒絕有異常的連線;採用頻率控制對連線次數、請求量等做限制;在協議包格式和指令正確性等方面做驗證。自己發出去的資訊,不應暴露自己的私有資訊,也不期望其他節點一定會給出立刻和正確的響應,必須採用非同步處理和校驗容錯的設計。
2 節點和客戶端互相不信任
客戶端,指在區塊鏈網路外,向區塊鏈發起請求的模組,如業務使用的java sdk、錢包客戶端等。客戶端和節點通過網路埠通訊。
如果客戶端掌握在不受控的人手裡,有可能會向節點發起大量的請求,或傳送一堆垃圾資訊,使節點疲於應對,甚至巧妙地構建漏洞攻擊資訊,試圖越權訪問,竊取資訊或使節點出錯。
同時,從客戶端的角度看,節點有可能不響應或響應緩慢,或者返回錯誤的資料,包括格式錯誤、狀態錯誤、表示收妥但其實不處理等,甚至別有用心的人會設定一個“假”節點和客戶端通訊,欺騙客戶端。節點做出這些與期望不符的反應,可能使客戶端執行出錯,功能受損。
為提升節點和客戶端的互信,可以為雙方分配數字證照,必須通過證照進行雙向握手,客戶端經過私鑰簽名才能對節點發起交易類請求,節點應對客戶端進行許可權控制,拒絕高危的介面呼叫,不要輕易開放節點管理介面、系統配置介面等。雙方對每次通訊的資料格式、資料有效性都進行嚴密校驗。
雙方在互動時也應該進行頻率控制,非同步處理,對每一個互動進行結果校驗,不能預設對方正確處理,必須獲取交易回執和處理結果進行確認。
當認為只和一個節點通訊並不能保證安全時,客戶端可以採用“f+1查詢”的思路,儘可能多地和幾個節點通訊。如果當前鏈的共識安全模型是“3f+1”,那麼,如果從f+1個節點讀到的資訊是一致的,結果是可以確認的。
3 不信任區塊高度
區塊高度是一個非常關鍵的資訊,代表整個鏈當前的狀態。向區塊鏈傳送交易、節點間進行共識、對區塊和狀態的校驗等操作都會依賴區塊高度。
某個節點在斷網或處理速度緩慢時,其區塊高度有可能落後於整個鏈,又或者某個節點惡意偽造資料時,其高度又可能超過整個鏈。在鏈出現分叉時,如某一個分叉上的區塊高度被另一個分叉超越,落後的分叉就會變得毫無意義。即使在正常的情況下,節點依舊有可能間歇性地落後於整個鏈一到幾個區塊,然後在一定時間內才可能追上最新高度。
如在PBFT共識模型裡,總數2/3以上節點在同一個高度時,全鏈就有機會達成共識繼續出塊。餘下的1/3的節點有可能和參與共識的節點高度不同,這時意味著從這個節點讀取到的資料,並不是全網最新的資料,只能代表鏈在該高度時的一個快照。
業務邏輯可以把區塊高度做為一個參考值,基於高度做一些判定邏輯,在確定性共識(如PBFT)的鏈上,採用f+1查詢等方法確認鏈的最新高度,在可能分叉的鏈上,需要參考“6個區塊確認”的邏輯,審慎選取可信的區塊高度。
4 不信任交易資料
交易(Transaction)代表一方向另一方發起了一個事務請求,交易可能導致資產的轉移、改變帳戶狀態或系統配置,區塊鏈系統通過共識後確認交易,使相關的事務生效。
交易必須帶上傳送者的數字簽名,交易裡所有資料欄位都必須包含在簽名裡,未經簽名的欄位存在被偽造的可能,不予採信。
交易資料在網路上廣播時,可以被其他人讀取,如交易資料裡包含隱私資料,傳送者則必須對資料進行脫敏或加密保護。
交易可能因為網路原因被重發,或者被其他人儲存下來刻意再次傳送,造成交易的“重放”,所以區塊鏈系統必須對交易進行防重,避免出現“雙花”。
5 不信任狀態資料
區塊鏈的狀態(State)資料是由智慧合約執行後生成的,理想情況下,每個節點的合約引擎一致、輸入一致、規則一致,那麼輸出的狀態就應該一致。但不同的節點可能安裝了不同的軟體版本,或者合約引擎的沙盒機制不夠嚴密引入了不確定性因素,甚至被侵入、篡改,或者存在其他莫名其妙的bug,都可能導致合約執行輸出結果不一致,那麼一致性和事務性就無法得到保障。
狀態的校驗是成本很高的事情,典型的校驗方法是使用MPT(Merkle Patricia Tree)樹,把所有狀態都塞到樹裡管理起來。MPT樹可以把所有的狀態歸結為一個Merkleroot Hash,節點之間在共識過程中確認交易執行後生成的狀態樹Merkleroot,確保狀態一致。
這棵樹結構複雜,資料量大,消耗不少的計算和儲存資源,很容易就成為了效能瓶頸。所以對狀態的校驗需要有更快、更簡單,且又穩妥的方案,如結合版本驗證、增量Hash驗證等演算法,輔以資料快取,可減少重複計算和優化IO次數,能在保證一致性、正確性的同時,有效地提升驗證效率。
6 不信任私鑰持有者
採用私鑰對交易以及其他關鍵操作進行簽名,再使用公鑰驗籤,是區塊鏈上最基礎的驗證邏輯。只要私鑰被正確使用,這個邏輯是安全的。
但私鑰僅僅是一段資料,只依賴私鑰則使用者是匿名的。在聯盟鏈面對的場景裡,需要使用許可型的身份,首先通過KYC、盡調、權威認證等現實世界的驗證方式確認身份,然後將身份和公鑰繫結並公示,或者結合PKI體系的數字證照發放公私鑰,這樣私鑰對應的身份是可知、可信、可控的。
私鑰可能會因丟失、洩漏而被他人盜用,或者因被遺忘導致資產損失。所以在私鑰的儲存上,需要考慮採用周全的保護方案,如加密儲存、TEE環境、密碼卡、USBkey、軟硬加密機等方案。在私鑰的管理上,則需要考慮金鑰丟失後如何安全的重置、找回。
加強版的私鑰使用思路有幾個,比如使用多籤、門限簽名等方式,每次交易時必須用多個私鑰進行簽名,私鑰可以保管在不同的地方,安全性高,但技術方案和使用體驗複雜。
還有一種是交易私鑰和管理私鑰分離。交易私鑰用於管理資產,管理私鑰用於管理個人資料,交易私鑰可以被管理私鑰重置,管理私鑰本身則通過門限、分片等演算法,分開儲存保管,以備重置或找回。
7 不信任其他鏈
在跨鏈的場景裡,每條鏈有自己的資產、共識,鏈之間的安全模型變得非常複雜,比如一條鏈上的記賬者串通造假,或者鏈出現了分叉、區塊高度回滾,這時如果鏈外的其他模組和鏈有不夠嚴謹的互動,都會造成資料不一致或資產損失。
如果不同的鏈採用的還是不一樣的平臺架構,那麼在工程上會更加複雜。
跨鏈、側鏈目前依舊是業界在研究和逐步實現的課題,主要目的是解決鏈和鏈之間的通訊,進行資產鎖定和資產交換,保證整個過程的全域性一致性、交易事務性,以及抗欺詐。從A鏈往B鏈轉移一個資產,必須要確保A鏈上的資產被鎖定或銷燬,且B鏈上一定能增加對應的一筆資產,在雙方可能分別出現分叉、回滾的時間窗裡,要有機制確保雙向的資產安全。
在現有跨鏈的方案裡,存在中繼、鏈間HUB等方式,這些系統的設計本身也要達到高度可信可靠的標準,安全等級應不低於甚至高於所對接的鏈,同樣也應採用多中心、群體共識的體系設計,整體複雜度可算是鏈的N次方了。
8 不信任網路層
區塊鏈節點需要和其他節點發生通訊,所以必須在網路上暴露自己的通訊埠,如果通過公網通訊,那麼相當於在公網上暴露了自己,很容易遭到類似滲透、DDOS這樣的網路攻擊。節點必須在網路層保護自己,包括在閘道器上設定IP黑白名單、設定埠策略、進行DDOS流量防護,且對網路流量、網路狀態進行監測,如果突發網路流量或連線數暴增,說不定,就是被人當肉雞或者正在脫庫進行時了。
非必要埠,切忌對公網開放,如用於做管理監控的RPC埠,只能對機構內部開放,在進行網路策略設定之前,一定要慎之又慎。
9 不信任程式碼
“Code is law”確實是一句響亮的口號,但是在程式設計師頭髮掉光之前,他寫的程式碼都可能有bug,只是看寫bug快還是修bug快而已。
無論是底層的程式碼還是智慧合約程式碼,都可能存在技術性或邏輯性的坑,但凡程式碼產生的資料和指令行為,都需要另一段程式碼對其進行嚴格地校驗,程式碼本身也需要進行靜態和動態掃描,包括採用形式化證明等技術進行全面地稽核驗證,以檢測可能的邏輯錯誤、安全漏洞或是否有資訊洩露。前段時間有一份公佈到github上的某酒店系統的程式碼,居然包括了mysql的連線使用者名稱密碼,且資料庫埠居然是向公網開放的,這種坑簡直不可想象。
開放出去的開原始碼,固然可以被人審查、反饋以提升安全性,也可能被人翻找漏洞、隨意修改,甚至惡意埋雷。但總的來說,開源還是利大於弊。在開源社群中,開發者會向專案提交PR(Pull Request)。稽核PR是很關鍵也很繁重的工作,值得安排專家並分配大量時間去做稽核。有開源專案的老司機透露,其專案核心模組的PR的稽核時間長達經年,否則“加了個功能引入兩個bug”那真是得不償失,更別說如果被植入漏洞埋雷了。
10 不信任記賬者
共識的流程大致可以抽象為,選出記賬者,記賬者釋出區塊,其他節點校驗和確認。公鏈裡記賬可以用“挖礦”的方式進行(如比特幣),礦工用大量的算力代價為它自己的誠信背書,又或者是用大量的資產權益抵押獲得記賬權(Pos和DPos等共識)。在聯盟鏈常用的PBFT/Raft等演算法裡,記賬者列表可以是隨機或輪換產生,記賬者給出提案,其他投票人多步提交,收集投票。按少數服從多數的原則,一般是2/3以上共識節點同意,共識才能達成。
從系統可用性角度看,記賬者有可能出錯、崩潰,或者執行緩慢,影響整個鏈的出塊。又或者記賬者可以只收錄手續費高的交易,拋棄一些交易,導致有些交易總是不能達成。有的記賬者還可以憑藉算力或暗箱運作,進行“預挖”或者“扣塊攻擊”,破壞博弈關係……
記賬者故障或作惡,超越了共識的安全閾值的話,將直接傷害整條鏈的價值基礎。根據不同的記賬模式,記賬者需要設計不同的容錯、校驗、抗欺詐演算法,執行激勵和懲罰機制,在執行過程中定期檢查記賬者的健康度,對於無力記賬或者作惡的記賬節點,全網不接受他們的記賬結果,並對其進行懲戒,甚至是踢出網路。
……
羅列起來還有很多,包括合約、證照、同步等等,每一個模組都有自己的功用和風險點,簡直罄竹難書。總之,區塊鏈做為分散式的多方協作的體系,接入了形形色色參與者,整個體系絕不是單個開發者或運營者所能單點把控,“善意推測”在這個領域已經不盡適用,整個世界步步驚心,處處冷箭,只能通過周密的演算法和繁雜的流程維繫共識和安全,簡而言之,沒有經過驗證的資訊,一個位元組都不能相信。
比起單一環境裡的軟體設計,區塊鏈領域的設計思路確實存在顛覆性,開發者要從“做功能,只容錯,不防騙”的思維模式裡跳出來,帶著“懷疑一切”的態度進行設計。
開發者在面向區塊鏈領域時,不能只是思考怎麼實現一個功能,而更要去思考整個流程會不會有出錯,會不會被人篡改資料、發掘漏洞、攻擊系統、欺詐其他參與者。要換位思考自己所實現的功能,會被別人用什麼方式使用,在不同的環境會有什麼表現,可能造成什麼後果。任何收到的資訊,任何流程輸入、輸出,都必須經過嚴格地校驗才能採信,開發者能做到這一點,才算是開啟了區塊鏈新世界的大門,才能在連續劇裡至少活到第二集。
分散式演算法、對稱非對稱加密、HASH、證照、安全和隱私等技術在區塊鏈領域大行其道,都是為了在保護資訊的同時,給資訊加上一層又一層的證明和可驗證因子,這使得整個系統變得複雜、繁瑣,但這是值得的,因為這樣才能共同驗證,構建“安全”和“信任”。
以上,寫給準備跳坑,或已經在坑裡的程式設計師。共勉。
FISCO
BCOS是完全開源的聯盟區塊鏈底層技術平臺,由金融區塊鏈合作聯盟(深圳)(簡稱金鍊盟)成立開源工作組通力打造。開源工作組成員包括博彥科技、華為、深證通、神州數碼、四方精創、騰訊、微眾銀行、亦筆科技和越秀金科等金鍊盟成員機構。
我們鼓勵機構成員、開發者等社群夥伴參與開源共建事業,有你在一起,會更了不起。多樣參與方式:1 進入微信社群,隨時隨地與圈內最活躍、最頂尖的團隊暢聊技術話題(進群請新增小助手微信,微信ID:fiscobcosfan);
2 訂閱我們的公眾號:【FISCO BCOS開源社群】,我們為你準備了開發資料庫、最新FISCO BCOS動態、活動、大賽等資訊;
3 來Meetup與開發團隊面對面交流,FISCO
BCOS正在全國舉辦巡迴Meetup,深圳、北京、上海、成都……歡迎您公眾號在選單欄【找活動】中找到附近的Meetup,前往結識技術大咖,暢聊硬核技術;4 參與程式碼貢獻,您可以在Github提交Issue進行問題交流,歡迎向FISCO BCOS提交Pull
Request,包括但不限於文件修改、修復發現的bug、提交新的功能特性。
程式碼貢獻指引: