以太坊链审计报告之go-ethereum链安全审计
字数 2220 2025-08-29 08:31:53

Go Ethereum (Geth) 安全审计报告解析与教学文档

1. 审计概述

1.1 审计背景

  • 审计时间:2017年4月
  • 审计对象:以太坊的Go语言实现(go-ethereum)
  • 审计机构:TrueSec
  • 代码质量评估:整体较高,开发者具备安全意识

1.2 主要发现

  • 未发现严重安全漏洞
  • 最严重问题:RPC HTTP开启时的Web浏览器同源策略绕过
  • 其他问题多为潜在风险和改进建议

2. 详细安全问题分析

2.1 P2P和网络安全问题

2.1.1 已知协议问题

  1. 对称加密中的two-time-pad缺陷

    • 导致通道缺乏保密性
    • 当前影响有限(仅传输公开区块链数据)
    • 相关issue:
      • https://github.com/ethereum/devp2p/issues/32
      • https://github.com/ethereum/go-ethereum/issues/1315
  2. 缺乏重放保护机制

    • 建议在协议下一版本中通过控制消息数量实现

2.1.2 内存分配过大风险

  1. 协议消息读取

    • 位置:rlpx.go中的ReadMsg方法
    • 问题:可分配16.8MB内存
    • 建议:限制为协议定义的10MB最大值
  2. 加密握手过程

    • 位置:encryption handshake
    • 问题:可分配65KB内存
    • 建议:限制握手消息大小

2.2 交易和区块处理问题

2.2.1 零除风险

  • 位置:downloader.go的qosReduceConfidence方法
  • 问题:依赖调用者保证d.peers.Len()不为零
  • 建议:所有非常数被除数应在除法前检查

2.2.2 代码复杂性

  • 影响文件:fetcher.go, downloader.go, blockchain.go
  • 问题表现:
    • 方法体过大(超过200行)
    • 同步机制复杂(混合使用互斥锁和通道)
    • Downloader结构体定义60行,含3个互斥锁和11个通道
  • 建议:重构简化代码

2.3 IPC和RPC接口问题

2.3.1 CORS配置问题

  • 问题本质:HTTP RPC接口默认允许所有域跨域访问
  • 影响版本:commit 5e29f4b之后
  • 技术细节:
    • 之前:空字符串→包含空字符串的数组→不设置CORS头
    • 之后:空数组→cors中间件默认允许所有域
  • 利用方式:
    var xhr = new XMLHttpRequest();
    xhr.open("POST", "http://localhost:8545", true);
    xhr.setRequestHeader("Content-Type", "application/json");
    xhr.onreadystatechange = function() {
      if(xhr.readyState == XMLHttpRequest.DONE && xhr.status == 200) {
        console.log("Modules: " + xhr.responseText);
      }
    }
    xhr.send('{"jsonrpc":"2.0","method":"rpc_modules","params":[],"id":67}')
    
  • 建议:
    • 显式限制CORS默认配置(如localhost)
    • 不依赖外部库的安全默认设置

2.4 JavaScript引擎和API问题

2.4.1 弱随机数种子

  • 位置:internal/jsre/jsre.go的randomSource方法
  • 问题:
    • crypto/rand失败时回退到UNIX时间作为种子
    • 虽然不用于敏感场景,但仍存在安全隐患
  • 建议:
    • crypto/rand失败时应报错而非回退
    • 明确文档说明PRNG非密码学安全

2.5 EVM实现问题

2.5.1 intPool滥用导致内存消耗

  • 问题:
    • intPool无大小限制
    • 特定opcode组合可廉价消耗内存
    • 示例合约消耗3.33e9 gas可分配10GB内存
  • 防护:
    • gaslimit限制提供一定保护
  • 建议:限制intPool大小

2.5.2 挖矿区块负值保护脆弱

  • 位置:core/evm.go的Transfer方法
  • 问题:
    • amount为有符号类型指针,可能为负
    • 区块处理过程缺乏显式负值检查
    • 仅依赖RLP序列化格式隐式阻止
  • 建议:
    • 区块处理中显式检查交易值
    • 或使用无符号类型强制正值

2.6 杂项问题

2.6.1 挖矿代码条件竞争

  • 位置:ethash/ethash.go的dataset方法
  • 问题:ethash datasets时间戳相关条件竞争
  • 修复建议:使用current.lock保护第一个current.used设置

2.6.2 过多第三方依赖

  • 现状:依赖71个第三方包
  • 风险:每个依赖都可能引入新攻击向量
  • 建议:
    • 评估是否所有依赖都必要
    • 考虑用自有代码替代部分依赖

3. 安全建议总结

3.1 必须修复问题

  1. RPC CORS默认配置问题
  2. 交易值负值检查
  3. 随机数生成器失败处理

3.2 推荐改进

  1. 限制内存分配大小
  2. 添加零除检查
  3. 重构复杂代码
  4. 限制intPool大小
  5. 修复条件竞争
  6. 减少第三方依赖

3.3 长期建议

  1. 协议层面改进加密和重放保护
  2. 建立更严格的代码审查流程
  3. 持续进行安全审计

4. 附录

4.1 参考资源

  • 原文报告: https://github.com/ethereum/go-ethereum/blob/master/docs/audits/2017-04-25_Geth-audit_Truesec.pdf
  • Go Ethereum: https://ethereum.github.io/go-ethereum/
  • Go Fuzz: https://github.com/dvyukov/go-fuzz/
  • 问题commit: https://github.com/ethereum/go-ethereum/commit/5e29f4be935ff227bbf07a0c6e80e8809f5e0202
  • CORS中间件: https://github.com/rs/cors
  • Otto JS引擎: https://github.com/robertkrimen/otto

4.2 版本升级建议

  • 使用旧版本Geth的用户应立即升级到最新版本
  • 定期关注官方安全公告和更新
Go Ethereum (Geth) 安全审计报告解析与教学文档 1. 审计概述 1.1 审计背景 审计时间:2017年4月 审计对象:以太坊的Go语言实现(go-ethereum) 审计机构:TrueSec 代码质量评估:整体较高,开发者具备安全意识 1.2 主要发现 未发现严重安全漏洞 最严重问题:RPC HTTP开启时的Web浏览器同源策略绕过 其他问题多为潜在风险和改进建议 2. 详细安全问题分析 2.1 P2P和网络安全问题 2.1.1 已知协议问题 对称加密中的two-time-pad缺陷 导致通道缺乏保密性 当前影响有限(仅传输公开区块链数据) 相关issue: https://github.com/ethereum/devp2p/issues/32 https://github.com/ethereum/go-ethereum/issues/1315 缺乏重放保护机制 建议在协议下一版本中通过控制消息数量实现 2.1.2 内存分配过大风险 协议消息读取 位置:rlpx.go中的ReadMsg方法 问题:可分配16.8MB内存 建议:限制为协议定义的10MB最大值 加密握手过程 位置:encryption handshake 问题:可分配65KB内存 建议:限制握手消息大小 2.2 交易和区块处理问题 2.2.1 零除风险 位置:downloader.go的qosReduceConfidence方法 问题:依赖调用者保证d.peers.Len()不为零 建议:所有非常数被除数应在除法前检查 2.2.2 代码复杂性 影响文件:fetcher.go, downloader.go, blockchain.go 问题表现: 方法体过大(超过200行) 同步机制复杂(混合使用互斥锁和通道) Downloader结构体定义60行,含3个互斥锁和11个通道 建议:重构简化代码 2.3 IPC和RPC接口问题 2.3.1 CORS配置问题 问题本质 :HTTP RPC接口默认允许所有域跨域访问 影响版本:commit 5e29f4b之后 技术细节: 之前:空字符串→包含空字符串的数组→不设置CORS头 之后:空数组→cors中间件默认允许所有域 利用方式: 建议: 显式限制CORS默认配置(如localhost) 不依赖外部库的安全默认设置 2.4 JavaScript引擎和API问题 2.4.1 弱随机数种子 位置:internal/jsre/jsre.go的randomSource方法 问题: crypto/rand失败时回退到UNIX时间作为种子 虽然不用于敏感场景,但仍存在安全隐患 建议: crypto/rand失败时应报错而非回退 明确文档说明PRNG非密码学安全 2.5 EVM实现问题 2.5.1 intPool滥用导致内存消耗 问题: intPool无大小限制 特定opcode组合可廉价消耗内存 示例合约消耗3.33e9 gas可分配10GB内存 防护: gaslimit限制提供一定保护 建议:限制intPool大小 2.5.2 挖矿区块负值保护脆弱 位置:core/evm.go的Transfer方法 问题: amount为有符号类型指针,可能为负 区块处理过程缺乏显式负值检查 仅依赖RLP序列化格式隐式阻止 建议: 区块处理中显式检查交易值 或使用无符号类型强制正值 2.6 杂项问题 2.6.1 挖矿代码条件竞争 位置:ethash/ethash.go的dataset方法 问题:ethash datasets时间戳相关条件竞争 修复建议:使用current.lock保护第一个current.used设置 2.6.2 过多第三方依赖 现状:依赖71个第三方包 风险:每个依赖都可能引入新攻击向量 建议: 评估是否所有依赖都必要 考虑用自有代码替代部分依赖 3. 安全建议总结 3.1 必须修复问题 RPC CORS默认配置问题 交易值负值检查 随机数生成器失败处理 3.2 推荐改进 限制内存分配大小 添加零除检查 重构复杂代码 限制intPool大小 修复条件竞争 减少第三方依赖 3.3 长期建议 协议层面改进加密和重放保护 建立更严格的代码审查流程 持续进行安全审计 4. 附录 4.1 参考资源 原文报告: https://github.com/ethereum/go-ethereum/blob/master/docs/audits/2017-04-25_ Geth-audit_ Truesec.pdf Go Ethereum: https://ethereum.github.io/go-ethereum/ Go Fuzz: https://github.com/dvyukov/go-fuzz/ 问题commit: https://github.com/ethereum/go-ethereum/commit/5e29f4be935ff227bbf07a0c6e80e8809f5e0202 CORS中间件: https://github.com/rs/cors Otto JS引擎: https://github.com/robertkrimen/otto 4.2 版本升级建议 使用旧版本Geth的用户应立即升级到最新版本 定期关注官方安全公告和更新