MilosMicun/solidity-security-patterns

GitHub: MilosMicun/solidity-security-patterns

展示 Solidity 智能合约经典安全模式的漏洞利用、修复方案和不变量验证的实战教学仓库。

Stars: 0 | Forks: 0

# Solidity 安全模式 本仓库模拟了 Solidity 系统中的真实故障模式,并演示了它们是如何被利用、缓解和衡量的。 每个模块遵循相同的准则: - 破坏系统 - 证明漏洞利用 - 应用修复 - 验证不变量 重点不在于模式本身——而在于 EVM 约束下的决策制定:正确性、安全性和成本。 ## 为什么这很重要 这些漏洞并非理论上的: - 重入攻击 已经耗尽了协议资金 - 访问控制漏洞 已导致全部资金损失 - MEV 漏洞 在生产环境中重新排序执行 - Gas 低效率 直接影响协议的生存能力 理解这些权衡是在链上交付安全系统的必要条件。 ## 系统概述 该仓库包含成对的实现: - 易受攻击的合约(真实攻击面) - 安全版本(已应用缓解措施) - 证明可利用性和正确性的测试套件 重点关注领域: - 重入攻击 - 算术安全 - 访问控制 - 交易排序 (MEV) - Gas 优化 ## 安全案例研究 ### 重入攻击 **漏洞** 状态在外部调用之后更新。 **利用** 攻击者在余额清除之前通过 `receive()` 重新进入 `withdraw()`,耗尽资金。 **根本原因** 控制流在状态转换完成之前被转移。 **不变量违规** 用户余额必须在任何外部交互之前减少。 ### 重入攻击缓解 **修复策略** - **Checks-Effects-Interactions (CEI)** (检查-生效-交互模式) 消除根本原因。 - **ReentrancyGuard** (重入守卫) 在运行时阻止嵌套执行。 **验证** - 漏洞利用在易受攻击的合约上成功 - 漏洞利用在受保护的实现上失败 **洞察** 重入攻击不是竞态条件——它是一个控制流问题。 安全性需要: - 正确的状态排序 - 运行时强制执行 ### 整数算术 **比较的模型** - Legacy (传统,回绕) - Checked (已检查,Solidity 0.8+) - Unchecked (未检查,手动负责) **根本原因** EVM 使用模运算 (`mod 2²⁵⁶`)。 安全性由编译器引入,而非执行层。 **故障模式** 无边界检查的算术运算会导致无声的状态损坏。 **不变量** 算术运算必须保持在定义的系统边界内。 **洞察** 溢出并没有被消除——它被抽象在编译器检查之后。 ### 访问控制 **漏洞** 缺少授权导致: - 所有权被夺取 - 无限制的提款 **根本原因** 授权边界未被执行。 **故障模式** 未经授权的行为者可以改变状态并提取资金。 **修复** - `onlyOwner` 修饰符 - 自定义错误 **不变量** 只有授权实体才能执行特权操作。 ### tx.origin 反模式 **漏洞** 基于 `tx.origin` 的授权。 **利用** 恶意合约转发调用: - `tx.origin` = 受害者 - `msg.sender` = 攻击者 检查通过 → 攻击者获得访问权限。 **修复** 使用 `msg.sender`。 **洞察** 授权必须遵循执行上下文,而非交易来源。 ### MEV / 前置交易 **漏洞** 用户输入在执行前在 mempool 中可见。 攻击者可以通过出价更高的 Gas 来重新排序交易。 **根本原因** 执行排序是对抗性的。 **故障模式** 状态转换依赖于公开可观察的输入。 ### Commit-Reveal (提交-揭示) 缓解 **方法** - commit (隐藏意图) - reveal (验证执行) ``` keccak256(abi.encodePacked(msg.sender, value, salt)) ``` **安全属性** - 隐藏意图 - 将承诺绑定到发送者 - 防止复制攻击 **局限性** 不保证公平性——仅消除了反应性优势。 **不变量** 结果决不能依赖于执行前的可观察输入。 **洞察** 安全性有时需要隐藏信息,而不是验证它。 ## Gas 分析 优化不仅仅是编写更简洁的代码——它关乎减少昂贵的 EVM 操作。 ### 结果 | Function | Inefficient | Optimized | Δ Gas | Δ % | |---|---|---|---|---| | Deployment | 564860 | 462483 | -102377 | -18.1% | | sumBalanceTimes | 6963 | 3906 | -3057 | -43.9% | | sumNumbers | 17858 | 15190 | -2668 | -14.9% | | setNumbers | 158984 | 157450 | -1534 | -1.0% | | setBalance | 44437 | 44437 | 0 | 0% | ### 解读 **sumBalanceTimes (-44%)** 通过缓存消除重复的 SLOAD。 **sumNumbers (-15%)** 减少循环和内存开销。 **setNumbers (-1%)** 受 SSTORE 主导。写入开销超过了优化。 **Deployment (-18%)** 通过 `immutable` 和自定义错误减少。 ### 关键洞察 Gas 成本遵循 EVM 原语: - 优化 SLOAD → 高影响 - 优化 SSTORE → 有限影响 - 优化语法 → 边际收益 ### 局限性 优化无法解决: - 昂贵的存储写入 - 糟糕的状态建模 - 写入密集型设计 如果模型本身效率低下,优化无法修复它。 ## 工程原则 - 状态是主要的攻击面 - 执行顺序定义安全边界 - 外部调用转移控制权 - 授权必须是显式的 - 编译器安全性不是保证 - 存储主导成本 - 优化前先测量 ## 项目结构 ``` solidity-security-patterns/ ├── src/ │ ├── gas/ │ │ ├── GasInefficient.sol │ │ └── GasOptimized.sol │ ├── mev/ │ │ ├── VulnerableGame.sol │ │ └── CommitRevealGame.sol │ ├── AccessControlVulnerable.sol │ ├── AccessControlFixed.sol │ ├── AccessControlBrokenTxOrigin.sol │ ├── Attacker.sol │ ├── TxOriginAttacker.sol │ ├── OverflowLegacy.sol │ ├── OverflowUnchecked.sol │ ├── OverflowChecked.sol │ ├── VulnerableBank.sol │ ├── GuardedBank.sol │ └── SafeBank.sol ├── test/ │ ├── gas/ │ │ └── GasOptimization.t.sol │ ├── mev/ │ │ ├── VulnerableGame.t.sol │ │ └── CommitRevealGame.t.sol │ ├── AccessControl.t.sol │ ├── AccessControlTxOrigin.t.sol │ ├── Overflow.t.sol │ └── Reentrancy.t.sol ├── foundry.toml └── README.md ``` ## 运行测试 ``` forge test forge test --match-path test/Reentrancy.t.sol forge test --match-path test/AccessControl.t.sol forge test --match-path test/mev/VulnerableGame.t.sol forge test --match-path test/gas/GasOptimization.t.sol --gas-report ``` ## 技术栈 - [Foundry](https://book.getfoundry.sh/) - Solidity `^0.8.20` - WSL2 / Ubuntu
标签:CEI 模式, CISA项目, DeFi 安全, EVM, Foundry, Gas 优化, MEV, Solidity, Streamlit, Web3 安全, Web报告查看器, 不变量测试, 以太坊, 区块链安全, 安全模式, 整数溢出, 智能合约审计, 漏洞复现, 访问控制, 重入攻击