慢霧:區塊鏈應用中常見的密碼學風險

作者:慢霧 
鏈接:https://mp.weixin.qq.com/s/0C7LMVFjc6nPtyQdDpXaHQ
聲明:本文為轉載內容,讀者可通過原文鏈接獲得更多信息。如作者對轉載形式有任何異議,請聯繫我們,我們將按照作者要求進行修改。轉載僅用於信息分享,不構成任何投資建議,不代表吳說觀點與立場。


背景概述
 
密碼學是 Web3 安全的基石,從私鑰的生成到交易的簽名,每一個環節都依賴於密碼學組件的正確與安全實現。然而,在 Web3 項目的實際開發中,研發團隊往往聚焦於業務邏輯與性能優化,對底層密碼學實現的細微之處缺乏足夠的警惕。使用不安全的隨機數生成器、錯誤地調用密碼學庫、或對算法特性的理解偏差,都可能引入致命漏洞,導致私鑰洩露、簽名偽造、進而造成無法挽回的資產損失。
 
通常,項目方會依賴安全審計來發現此類問題。然而,審計作為一種事後驗證手段,難以覆蓋項目全生命週期。許多漏洞根植於開發階段初期選型與設計,若團隊自身不具備基礎的密碼學安全知識,則無法從根源上規避風險。
 
因此,慢霧安全團隊開源了區塊鏈應用中常見的密碼學風險,希望將一線攻防中積累的、關於密碼學誤用的典型案例與最佳實踐沉澱下來。我們期望項目方團隊能夠在開發之初便築牢密碼學安全防線,最終建立起自主、持續的安全編碼能力。
 
 
本文僅羅列部分內容,完整內容首發於 GitHub,歡迎大家到 GitHub 上 Watch、Fork 及 Star:https://github.com/slowmist/Common-Cryptographic-Risks-in-Blockchain-Applications
 

0x01 私鑰隨機數安全

 

1. 使用 JavaScript Math.random 或基於時間的種子生成隨機數


  • 嚴重性:


  • 描述:JavaScript 的 Math.random() 是一個偽隨機數生成器(PRNG),不適合用於加密安全的場景。其實現依賴於瀏覽器或 JavaScript 引擎(如 V8 的 Xorshift128+),種子和算法通常不可控且不可預測性不足,可能導致生成的隨機數序列被攻擊者猜測或重現。


  • 利用場景:這在生成加密密鑰、會話令牌、CSRF 令牌或遊戲隨機事件時,可能導致密鑰被破解、會話劫持或遊戲作弊。


  • 建議優先使用 crypto.getRandomValues() (Web Crypto API) 生成加密安全的隨機數,適用於密鑰、令牌等敏感場景。


2. 使用 Java 的不安全隨機數生成方式生成私鑰


  • 嚴重性


  • 描述:Java 的 java.util.Random 或 java.util.concurrent.ThreadLocalRandom 是非加密安全的偽隨機數生成器(PRNG),其種子和算法(如線性同餘生成器)可預測且熵不足。如果使用這些方法生成加密私鑰(如 RSA、ECDSA),生成的密鑰可能存在可預測性,容易被攻擊者推導或重現。


  • 利用場景:在基於 Java 的 Web 應用中,使用 Random 生成的密鑰可能被攻擊者利用,破解 TLS 會話或偽造 JWT 令牌。


  • 建議:改用 java.security.SecureRandom,它是為加密場景設計的隨機數生成器,提供高熵輸出,適合生成私鑰。或者優先使用標準庫或框架(如 KeyPairGenerator、KeyFactory)生成密鑰。


  1. Android 系統在某些版本中 SecureRandom 未能正確初始化


  • 嚴重性:


  • 描述:在某些 Android 版本(特別是早期版本,如 4.1-4.3),java.security.SecureRandom 未能正確初始化,導致其生成的隨機數熵不足。這通常是由於系統熵池(如 /dev/urandom)未被充分填充,或者 SecureRandom 的實現缺陷,致使生成的隨機數序列可預測性較高,用於私鑰生成時顯著降低安全性。


  • 利用場景:在受影響的 Android 設備上,使用 SecureRandom 生成的 Bitcoin 私鑰可能被破解,導致資金被盜。


  • 建議:在調用 SecureRandom 前,顯式調用 SecureRandom.setSeed() 並結合高熵來源(如用戶輸入或硬件傳感器數據)增強隨機性。


  1. 私鑰生成過程中存儲隨機數的變量類型空間太小


  • 嚴重性:


  • 描述:在私鑰生成過程中,若使用空間太小的變量類型(如 32 位整數)存儲隨機數,會限制隨機數的範圍和熵值,導致生成的私鑰強度不足。


  • 利用場景:攻擊者可利用隨機數範圍受限的弱點,通過暴力破解或預計算攻擊(如彩虹表),快速猜測私鑰。例如,在 Profanity 工具的案例中,攻擊者通過分析生成的地址模式,成功破解多個 Ethereum 錢包,竊取大量資金。


  • 建議:使用足夠大的變量類型(如 256 位或更高)存儲隨機數,以支持完整密鑰空間(如 secp256k1 曲線的 2^256 範圍)。


  1. Libbitcoin Mersenne Twister 弱熵漏洞


  • 嚴重性:


  • 描述:Libbitcoin Explorer(版本 3.0.0 至 3.6.0)的 bx seed 命令使用 Mersenne Twister(MT19937) 偽隨機數生成器(PRNG) 生成錢包種子,種子僅由 32 位系統時間(high_resolution_clock) 初始化。這導致熵空間被限制在 2^32(約 43 億)個可能值,遠低於安全的 128 位或 256 位熵要求。攻擊者可通過暴力破解重現種子,進而推導私鑰,危及用戶資金安全。此漏洞被稱為“Milk Sad”,因其生成的首個種子短語以“milk sad”開頭。


  • 利用場景:get_clock_seed() 返回僅 32 位的系統時間戳(uint32_t),用作 Mersenne Twister 的種子。std::mt19937 雖生成看似隨機的輸出,但其熵受限於 32 位種子,無法提供 128 位或更高安全級別。pseudo_random_fill 填充輸出時,擴展到 256 位僅是偽隨機擴展,未增加實際熵。


  • 建議:替換 Mersenne Twister,改用加密安全的隨機數生成器(如 /dev/urandom、C++ 的 std::random_device 搭配高熵源,或 OpenSSL 的 RAND_bytes)。


6. OpenSSL 隨機數生成器安全風險


  • 嚴重性:


  • 描述:OpenSSL 密碼庫的隨機數生成器 RAND_pseudo_bytes() 用於將 num 偽隨機字節放入 buf,但存在安全設計缺陷。由 RAND_pseudo_bytes() 生成的偽隨機字節序列如果長度足夠長,則是唯一的,但並不一定是不可預測的。它們可以用於非加密目的,並且可以在某些加密協議中用於特定目的,但通常不用於密鑰生成等。


  • 漏洞示例:低熵密鑰洩露(LESLI),即攻擊者通過獲取 nonce 並通過暴力枚舉所有可能的 PIN 碼和 RNG 狀態,可以恢復原始的 PIN 值。

     

  • 建議:避免使用 RAND_pseudo_bytes,完全替換為 RAND_bytes 並檢查其返回值。

     

0x02 ECDSA 安全

 

1. secp256r1 後門問題


  • 嚴重性:


  • 描述:secp256r1(也稱 NIST P-256)是一種廣泛使用的橢圓曲線密碼算法,但存在對其生成參數潛在後門的擔憂。標準化過程中,參數由 NSA 提供,缺乏透明的生成過程,可能被故意設計為包含弱點,允許特定攻擊者(如 NSA)利用隱藏的數學關係解密數據或偽造簽名。


  • 利用場景:攻擊者可能利用後門(若存在)通過已知參數的數學特性,快速計算私鑰或預測隨機數生成器的輸出,從而破解加密通信、偽造數字簽名,或竊取基於 secp256r1 的加密系統(如 TLS、Bitcoin、SSH)中的敏感數據。


  • 建議:考慮切換到 Ed25519 或 Secp256k1 等透明生成參數的曲線,降低後門風險。


2. secp256k1 中 k 值弱隨機導致私鑰洩露


  • 嚴重性:


  • 描述:在 secp256k1 曲線的 ECDSA 簽名過程中,簽名需要一個隨機數 k (nonce)。如果 k 值由弱隨機數生成器生成(例如,低熵源、不安全的 PRNG 或可預測的種子),攻擊者可能通過分析簽名數據推測 k 值,進而利用 ECDSA 的數學特性直接計算私鑰。這種漏洞通常源於使用不安全的隨機數生成器(如 rand()、Math.random())或環境熵不足(如虛擬機或嵌入式設備)。


  • 利用場景:攻擊者可通過收集少量簽名數據(例如,r 和 s 值),結合弱隨機數的可預測性,重構 k 值並推導私鑰。在區塊鏈場景(如 Bitcoin、Ethereum),這可能導致錢包私鑰暴露,資金被盜。例如,若 k 值基於時間戳或固定種子生成,攻擊者可通過暴力破解或模式分析快速恢復私鑰。類似問題曾出現在早期加密錢包實現中,因使用弱隨機源生成 k 值而被破解。


  • 建議:使用確定性 k 值生成(RFC 6979),基於私鑰和消息哈希生成唯一的 k 值,避免依賴隨機數生成器的質量。


3. secp256k1 中 k 值重用導致私鑰洩露


  • 嚴重性:


  • 描述:在 secp256k1 橢圓曲線(廣泛用於比特幣等加密貨幣)上使用 ECDSA 簽名時,如果兩次簽名使用了相同的隨機數 k (nonce),則簽名中的 r 值將相同。攻擊者可通過分析這兩組簽名(r, s1) 和(r, s2) 及對應的消息哈希 h1、h2,推導出私鑰。這種漏洞源於 ECDSA 簽名方程的數學結構,k 的重用使得攻擊者能夠建立方程組,直接解出私鑰 d。


  • 建議:遵循 RFC 6979 標準,根據私鑰和消息哈希生成確定性但不可預測的 k 值,防止重用。


4. ECDSA 簽名值的可鍛造性


  • 嚴重性:


  • 描述:ECDSA(橢圓曲線數字簽名算法)的簽名值(r, s) 存在可鍛造性,即給定一個有效簽名(r, s),可以生成另一個等價的有效簽名(r, -s mod n),其中 n 是橢圓曲線的階。這種數學特性源於 ECDSA 簽名驗證的模運算對稱性。如果實現未規範化簽名(例如,強制使用“低 s 值”),攻擊者可修改簽名而不影響其有效性,可能繞過簽名驗證機制或破壞某些協議的唯一性要求。


  • 利用場景:攻擊者可利用簽名可鍛造性在區塊鏈(如 Bitcoin、Ethereum)或協議中製造問題。例如,在 Bitcoin 交易中,攻擊者可修改交易簽名的 s 值生成新簽名,改變交易 ID (txid),導致交易被拒絕或引發雙花風險。此外,在某些智能合約或多重簽名協議中,未規範化簽名可能被用來繞過驗證邏輯,造成資金損失或協議失效。2013 年,Bitcoin 網絡曾因簽名可鍛造性引發交易可塑性(malleability) 攻擊,影響 Mt. Gox 等交易所。


  • 建議:強制使用“低 s 值”(s ≤ n/2),遵循 RFC 6979 或 BIP-66 標準(Bitcoin 社區採用),拒絕非規範簽名以消除可鍛造性。


5. ECDSA 與 Schnorr 簽名共用隨機數 k 導致私鑰洩露


  • 嚴重性:


  • 描述:在橢圓曲線數字簽名算法(ECDSA) 和 Schnorr 簽名中,如果在生成簽名時共用相同的隨機數 k (nonce),攻擊者可以通過分析簽名來推導出私鑰。這種漏洞源於兩種簽名方案的數學結構相似性,允許通過已知的簽名方程反推出私鑰。無論是在同一系統內多次簽名,還是在不同簽名算法間重用 k,都會導致私鑰完全暴露,進而使攻擊者能夠偽造簽名或控制相關賬戶。


  • 建議:RFC6979 中輸⼊參數可以包含“addition data”,在派⽣ k 時,可以將簽名算法的信息填⼊該字段,如此可以在算法的維度上安全重⽤ k。


6. ECDSA 不需要提供簽名值對應的消息 m 時可偽造簽名值


  • 嚴重性:


  • 描述:在驗證 ECDSA 簽名時,若驗證過程僅要求提供消息的哈希值而非原始消息本身,則攻擊者可以在不知道私鑰的情況下,基於已知的合法簽名,構造出能通過驗證的偽造簽名。這個漏洞利用了 ECDSA 驗證機制的數學特性,允許攻擊者選擇特定的數值組合創建偽造簽名,而無需知道對應的原始消息或私鑰。


  • 建議:驗證簽名時必須要求提供原始消息 m,而不僅僅是哈希值。


7. ECDSA 簽名中的 Nonce 側信道攻擊漏洞


  • 嚴重性:


  • 描述:LadderLeak 是一種存在於 ECDSA 實現中的側信道漏洞,攻擊者可以通過緩存時序分析獲取簽名過程中使用的隨機數(nonce) 的最高有效位信息,但洩露概率低於 100%(即"不到 1 比特"的信息)。該漏洞存在於 OpenSSL 1.0.2 和 1.1.0 分支以及 RELIC 工具包 0.4.0 版本中,特別影響了基於曲線 sect163r1 和 NIST P-192 的 ECDSA 實現。該漏洞源於 Montgomery 梯形算法實現中座標處理不當導致的微小時間差異。攻擊者可以觀察到這種時間差異,並利用統計方法推斷出隨機數 k 的最高位。即使這種洩露率低於 100%(如對 P-192 為 99%,對 sect163r1 為 97.3%),攻擊者仍然可以通過改進的 Bleichenbacher 傅立葉分析方法,收集足夠數量的簽名後完全恢復私鑰。


  • 漏洞示例:針對 OpenSSL 的實現,漏洞表現在二進制曲線情況(如 sect163r1)和素數曲線情況(如 NIST P-192) 


    1. Filecoin BLS 簽名驗證中的可延展性漏洞


    • 嚴重性:


    • 描述:在 Filecoin 的 Lotus 實現中發現了 BLS 簽名驗證存在可延展性漏洞。BLS 簽名可以以序列化(serialized) 和壓縮(compressed) 這兩種不同的形式表示,這兩種形式都可以通過 BLST 庫的 VerifyCompressed 方法成功驗證。但 Lotus 的區塊驗證邏輯使用包含簽名的區塊頭 CID 來識別區塊唯一性,這導致了以下安全問題:同一個區塊如果使用兩種不同形式的 BLS 簽名,將被視為兩個不同的區塊,因為它們的 CID 不同。攻擊者可以通過提交包含相同內容但簽名格式不同的區塊來利用這一漏洞,繞過重複區塊檢測,可能導致區塊鏈分叉、雙花攻擊或共識故障。


    • 建議:在驗證簽名之前,將所有簽名轉換為統一格式(要麼全部使用序列化格式,要麼全部使用壓縮格式)。


    2. BLS 庫中的零值相關漏洞與"零值分裂"攻擊


    • 嚴重性:


    • 描述:研究人員在四個主流 BLS (Boneh-Lynn-Shacham) 加密庫和 BLS 標準草案中發現了一系列與零值處理相關的嚴重安全漏洞,被統稱為"splitting zero"(零值分裂)攻擊。這些漏洞源於對加密算法中特殊值"0"處理的缺陷,可能導致簽名驗證繞過、私鑰恢復、拒絕服務和其他嚴重安全問題。特別值得注意的是,GitHub 報告還提到了一些額外的零值相關漏洞,包括:在 supranational/blst 庫中,零長度簽名或零長度消息會導致程序崩潰;在模 p 運算中,inverse(0) mod p = 0,但 inverse(p) mod p = 1 的處理錯誤。BLS 簽名方案因其獨特的聚合特性而廣泛應用於區塊鏈和分佈式系統,這些漏洞可能對依賴這些庫的大型系統產生重大安全影響。


    • 漏洞示例:根據研究文檔,“零值分裂”攻擊主要包括零簽名驗證繞過、零公鑰攻擊、庫崩潰漏洞、模運算中的零值問題,以及聚合簽名中的零值操縱。
       

    • 建議:明確定義並一致實現對零值(零長度輸入、零點、零標量等)的處理策略。


    3. BLS 多重簽名中的 Rogue Key Attack 漏洞


    • 嚴重性:


    • 描述:在 BLS 簽名方案中,聚合公鑰和簽名僅通過簡單求和實現。攻擊者可以創建“rogue key”(流氓密鑰),通過設置秘密密鑰為 0 並計算誠實密鑰的加法逆來抵消誠實參與者的貢獻。


    • 建議:實施 Proof-of-Possession (PoP) 機制的嚴格驗證,避免依賴簡單求和聚合;考慮使用非線性化聚合或額外隨機性。

       

    0x06 RSA 安全

     


    1. 哈希碰撞生日攻擊


    • 嚴重性:


    • 描述:哈希生日攻擊基於概率學中的"生日悖論",利用這一原理可以大幅降低找到哈希碰撞所需的計算複雜度。對於 n 比特的哈希函數,理論上需要 2^n 次嘗試才能找到特定的碰撞,但利用生日攻擊,只需約 2^(n/2) 次嘗試就能找到任意兩個輸入產生相同哈希值的概率達到 50%。


    • 漏洞示例:假設使用 MD5 哈希函數(128 位輸出),攻擊者可以通過生成約 2^{64} 個變體消息來找到碰撞。例如,攻擊者創建兩個不同合同文件 A 和 B(A 是合法的,B 是篡改的),使得 MD5(A) = MD5(B)。如果系統使用 MD5 驗證簽名,攻擊者可以用 A 的簽名偽造 B,導致如 2004 年 Flaming 攻擊中 MD5 碰撞用於生成假證書,或 2012 年 Flame 惡意軟件利用碰撞繞過 Windows 更新驗證。


    • 建議:採用抗碰撞性強的現代哈希算法,如 SHA-256、SHA-3 或 BLAKE2,避免使用 MD5 和 SHA-1 等已被證明不安全的算法。


    2. 哈希函數長度擴展攻擊


    • 嚴重性:


    • 描述:哈希函數長度擴展攻擊(Length Extension Attack) 是一種針對使用 Merkle-Damgård 結構的哈希函數(如 MD5、SHA-1和 SHA-2 系列)的密碼學攻擊。攻擊者利用這類哈希函數的內部工作機制,在知道 H(message) 和 message 長度的情況下,無需知道 message 本身,就能夠計算出 H(message||padding||extension) 的值,其中 extension 是攻擊者選擇的任意數據。這種攻擊之所以可行,是因為 Merkle-Damgård 結構的哈希算法將輸入分割為固定長度的數據塊,並且每個塊的哈希值依賴於前一個塊的哈希狀態。這意味著攻擊者可以從一個已知的哈希狀態繼續計算,添加更多數據塊,而無需知道產生該狀態的原始數據。這類漏洞在 Web 應用、API 驗證、身份認證系統和區塊鏈應用中尤為危險,特別是當系統使用形如 H(secret||message) 的簡單驗證模式時。


    • 建議:採用 SHA-3、BLAKE2 等非 Merkle-Damgård 結構的現代哈希算法,這些算法天然不受長度擴展攻擊影響。

       

    0x08 AES 安全

     


    1. 弱 Fiat-Shamir 變換


    • 嚴重性:


    • 描述:Fiat-Shamir 變換是將交互式的零知識證明協議轉化為非交互式的證明協議的一個重要方法,它將證明者和驗證者中的隨機挑戰替換成散列函數的輸出⁠。冰心漏洞(Frozen Heart) 是指在實現 Fiat-Shamir 變換時,使用了"弱 Fiat-Shamir"變換,即只對證明者的部分消息進行散列而不散列公開信息(如參數、公開輸入等)。這導致攻擊者可以在不知道秘密值的情況下,通過預計算公鑰 A 來偽造證明,欺騙驗證者。該漏洞影響了多個主流零知識證明系統,包括 Bulletproofs、Plonk、Spartan 和 Wesolowski 的 VDF 等。


    • 建議:確保在 Fiat-Shamir 變換實現中,將所有公共輸入數據也加入到隨機數生成過程中。


    2. GG18 和 GG20 Paillier 密鑰漏洞


    • 嚴重性:


    • 漏洞描述:該漏洞存在於兩個廣泛使用的多方計算(MPC) 協議 GG18 和 GG20 的規範中,影響了超過 10 個錢包和庫(包括幣安託管服務)。漏洞的根源在於協議實現中未檢查攻擊者的 Paillier 模數 N 是否包含小因子或是否為雙素數。攻擊者可以利用此漏洞與 MPC 協議中的簽名方交互,竊取他們的秘密分片並最終獲得主秘密密鑰,從而完全提取私鑰並盜取加密錢包中的所有資金。


    • 建議:確保簽名方的 Paillier 公鑰經過小素數因子檢查,防止攻擊者使用包含小因子(如 2^20 大小的素數)的惡意模數。

       

    總結

     

     

    慢霧安全團隊開源——區塊鏈應用中常見的密碼學風險,旨在系統性地揭示私鑰生成、數字簽名、哈希函數及對稱加密等核心環節中潛藏的高危安全風險。Web3 項目方可以參考本文對各類漏洞的原理剖析、利用場景及修復建議,深化對密碼學安全的理解,規避常見的實現陷阱,從而更有效地保障項目和用戶的資產安全。



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