以太坊链审计报告之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 已知协议问题
-
对称加密中的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中间件默认允许所有域
- 利用方式:
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 必须修复问题
- 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的用户应立即升级到最新版本
- 定期关注官方安全公告和更新