區塊鏈數據「全局一致」、「難以篡改」這兩個特性已經廣爲人知,是區塊鏈營造「信任」的基石。爲了達到這兩個效果,區塊鏈的共識、同步、校驗等技術細節足可大書特書,而本文要從「我篡改了區塊鏈數據」講起。node
FISCO BCOS開源聯盟鏈社區如今至關活躍,天天都會產生大量的討論,你們也會饒有興趣地研究和挑戰區塊鏈如何作到「難以篡改」。咱們注意到,尤爲在FISCO BCOS支持MySQL數據庫做爲數據存儲引擎後,隔一陣子就有同窗在羣裏問:「我手動修改了我節點鏈接的數據庫裏某個狀態數據,這是否是就是篡改了區塊鏈數據呢?」git
直觀地舉個例,如鏈上有個智能合約,管理特定資產餘額,在數據庫合約表裏,通過共識的Alice的餘額原本是100,這時有人打開MySQL客戶端,找到那個合約對應的Table,把Alice的餘額update成10000。github
這時他表示:「你看,我調用合約的查詢接口,查出來Alice的餘額確實是10000,這就不對了嘛,並且,鏈還在出塊,根本不防篡改嘛!」。算法
爲什麼這類問題最近多起來了?咱們分析了下,猜測主要是因爲MySQL數據庫用戶基礎良好,體系比較成熟,給用戶提供友好的命令行或圖形化交互工具,FISCO BCOS提供了一種Table風格的合約開發模式,表結構設計得清晰直觀,對於用戶來講,一方面理解和管理起來更容易了,另外一方面順手update甚至delete一下都是小意思。數據庫
下圖僅爲示例數據,採用KVTable合約方式,建立了名爲t_kv_node的合約表,系統自動加了「u_」前綴,可見,這個表結構和數據一目瞭然。編程
而以前只採用LevelDB或RocksDB做爲存儲引擎,這兩個文件型數據庫交互工具比較少,在用戶面前的存在感不強,操做相對晦澀,主要經過API編程訪問,數據用肉眼難以辨別的Hash key尋址,動手修改數據庫的case就少了一些(但也不是不可能)。緩存
因此,熱點問題浮出水面,前提是用戶能夠更方便地修改底層數據了,而不是這個問題以前不存在。安全
這時咱們會建議用戶試一下,針對Alice的餘額,發起一個交易,好比給Alice充值,或者讓Alice轉帳操做,這時,修改過數據的節點將沒法參與共識。由於該節點上算出來的Alice的餘額和其餘節點結果不一樣,其餘節點依舊按100的餘額進行計算,而不是10000,顯然結果是對不齊的。服務器
複習下PBFT的容錯模型:定義「f」爲可容錯節點數,網絡中共識節點總數應等於或多於3f+1。即鏈上有4個共識節點時,可容錯的f=1,共識節點總數爲7個時,f=2,以此類推。網絡
若是未修改過數據的節點數知足PBFT要求的2f+1的數量,鏈依舊能夠出塊。但被修改過的節點,一旦有交易涉及髒數據,就像踩到了雷同樣,今後再沒法與鏈共識、同步,至關於被拋棄了。這種節點能夠稱爲「拜占庭節點」,即做惡或出錯的節點,具有節點准入控制能力的聯盟鏈甚至會將拜占庭節點隔離出去。
還有一種可能性是,手動修改了數據庫裏的數據,但節點內存裏還恰好緩存了一份副本,並無被修改,因此經過節點對這個數據的查詢、交易仍是正常的,甚至會用正確的結果把數據庫裏被篡改過的數據覆蓋掉,不過這是機率性事件,取決於緩存的大小和當時包含的數據項。
*注:對於採用PoW或其餘共識機制的鏈來講,容錯模型有所不一樣,但在容錯範圍內的少數節點被篡改,也不會影響鏈的共識。
有的同窗可能會繼續刨根問底:「那我多修改幾個節點的數據是否是就篡改了?」,通常提出這個問題的同窗是面向他本身部署的開發測試環境,全部節點都在他手上,因此能夠隨便改。
在真實的聯盟鏈環境上,節點分別掌握在不一樣機構手裏,要修改,首先得侵入他人的網絡、得到服務器和數據庫權限、發起修改再全身而退。事實上,在注重安全防禦的商業化環境裏,這是很是艱難、幾乎不可能作到的事情。
從機構粒度來看,單個機構掌握的節點數,應該低於共識算法可容錯的數量。好比,鏈上總共有7個共識節點,那麼單個機構掌握的共識節點不該多於2個,這樣能夠避免機構內部強行修改本身掌握的節點數據,或一個機構的全部節點都意外出錯、掉線(好比機房光纖都被挖斷了),致使鏈沒法出塊。
考慮區塊鏈數據本地驗證的機制,好比區塊之間的Hash關係、狀態的Merkle樹結構、共識節點的簽名等,按數據的互驗關係順藤摸瓜進行檢測,彷佛有必定機率能夠本地檢測出數據異常。
但進一步想,對某個數據的查詢,區塊鏈的本地校驗範圍是有限的,通常不會超出單個區塊或者一棵merkle樹,因此若是篡改者比較熟悉區塊鏈數據的結構和本地校驗邏輯,也能夠順着數據校驗關係,從狀態值開始,把merkle樹、區塊Hash等關鍵數據所有改掉。
甚至更完全地,從創世塊開始,把全部的區塊、系統配置(對於PoW,能夠修改挖礦難度以加速出塊)、PBFT的共識者列表等等,都按他的邏輯改一遍,這樣這條本地數據鏈依舊是校驗自洽的,只是沒法和其餘節點共識了。
這種改法,聽起來須要很多力氣活,但對於一個有決心、有能力的篡改者來講,改改本地數據這個事情其實並不難,難的只是去改別的機構數據而已。
到了這個份上,就至關於一我的鐵了心要「騙本身」,那神仙都沒有辦法了。一旦把本地數據修改的權限交給了不適當的人,最壞狀況下,整條鏈沒有一個字節是對的。
可是,本地數據再錯,也只會影響本身,影響不了別人,一旦和其餘節點進行共識,就會被發現,甚至被懲戒,整個效果會有一點掩耳盜鈴的意思。
再進一步,那位同窗又會問:「爲何區塊鏈不能馬上發現、而且阻止我篡改數據?也許我只是無心手誤呢」。坦率說,這有點對區塊鏈指望太高了。
區塊鏈系統並不是無所不能,也不會包辦一切,區塊鏈並不會阻止用戶對本身的服務器、軟件、數據庫等施加操做,就像法律不能也不該去阻止你打碎家裏的杯子同樣。
本質上,區塊鏈的一致性、難以篡改性是面向「全局」的,是由多方博弈和協做達成的,當鏈上交易牽涉錯誤數據時,共識機制能夠檢測並拒絕已被篡改的數據,保證鏈上剩餘的大多數健康節點繼續共識出塊。而節點本地不參與共識的數據,共識機制鞭長莫及。
那麼,區塊鏈爲何不能主動檢測和糾正錯誤,保證每一個節點上的數據一致性?首先,鏈上的數據很是龐雜,用戶直接登入數據庫手動修改少許數據,區塊鏈節點並不知道哪一條數據被修改了,沒法觸發檢查。
若是區塊鏈系統按期巡檢全部數據,並將全部數據和其餘節點進行比對,可想而知,這樣作的話,網絡、磁盤和計算開銷會很是大。
關鍵是,這並不解決問題,由於從數據被篡改後到檢測出來的時間窗裏,哪怕髒數據只存在了幾十毫秒,但這時若是不幸有應用來查詢數據,依舊會獲得篡改後的結果。對要求苛刻的業務來講,過後檢測未必是最佳選項,由於有可能已經形成了業務損失,屆時能作的最多就是告警和衝正了。
固然,也能夠結合數據庫的操做監控、binlog等輔助機制,加速響應速度和檢測效率。方法仍是有的,如上所述,只是性價比較低,也不完全解決問題,只有對數據修改極其敏感,且業務上接受延時發現和修訂的特定場景,纔會考慮將其做爲補救措施。咱們把這部分歸類到運營管理工具裏,根據場景需求來實現。
還有一種方法,能夠部分解決查詢問題:f+1查詢。即查詢數據時,不管是查區塊數據,仍是合約的狀態數據,不妨多查幾個節點,查詢節點數多於 f 便可。
如鏈上有個7個節點時,f=2,用戶查詢本身節點以外,繼續發出網絡請求去查詢其餘機構的2個節點,共查詢3個節點,若是獲得的數據都是一致的,則表示數據必定是正確的,反之,必定是這3個節點裏出了問題。
可是,要執行f+1查詢,前提是其餘機構開了查詢接口權限,讓你鏈接上去查詢。在不少安全防禦嚴密的聯盟鏈上,通常只打開節點之間P2P互聯的網絡端口,不會輕易給其餘機構提供數據查詢權限。再則,在網絡上發起屢次查詢,其異步性、時效性、成功率和性能表現都會帶來更多變數。
綜上所述,對節點本地的數據,就像打地鼠,冒頭的(發出交易參與共識,或進行f+1查詢),區塊鏈全局共識和容錯機制能發現,沒有冒頭僅蹲在用戶硬盤裏的,只能用戶本身負責了。
區塊鏈經過網絡博弈、多方校驗實現了全網的容錯防做惡,而區塊鏈同步給到各節點的本地數據,須要用戶自行妥善管理保存。
從信任傳遞來看,首先用戶得「信本身」,若是連本身都沒法相信,說明系統和數據管理有漏洞,莫說是修改數據了,在本地系統的整個鏈路上,包括區塊鏈軟件、SDK、業務服務都有可能出錯和篡改做假,這樣的環境有何信任可言?
節點持有者必須很是審慎,首先不要手癢或手誤去改數據,而後關鍵是要創建周全的制度,包括管理策略和技術防禦,好比,主機訪問控制、數據庫登陸和操做權限控制、操做審計、日誌審計等,以免本機構內有人越權訪問監守自盜,或者被外部滲透。
萬一數據出錯,區塊鏈比中心化系統好一點的就是,還有可能經過與其餘節點互相校驗檢測出來,這時則應該進行告警、查證、補正和追責,以及在有條件和有必要的前提下,善用f+1查詢方法,給查詢操做加一點點保險。
另外,建議按期備份節點數據到安全的離線設備上,這樣不管是出現意外仍是人爲的數據問題,依舊能夠從冷數據裏快速恢復,保證必定的RTO(復原時間目標)和RPO(恢復點目標)。
而區塊鏈的健壯性在於,不管單個角色怎麼折騰本身的節點和數據,對全局是沒有影響的,只有修改者本身受損。任憑窩裏翻天覆地,鏈上依舊雲淡風輕,其「全局一致」、「難以篡改」的定律依舊成立,鏈仍然是信任的錨點,這就是區塊鏈的魅力。
FISCO BCOS的代碼徹底開源且免費
下載地址↓↓↓
https://github.com/FISCO-BCOS...