Q11 · 智能合约与 Solidity

Solidity 常见安全问题有哪些?

Solidity安全重入攻击

⚡ 速记答案(30 秒)

  • 重入攻击:状态更新顺序错误,外部合约回调再调用当前合约
  • 整数溢出/下溢(旧版本),可用 SafeMath/编译器检查
  • 授权问题approve 逻辑、onlyOwner 修饰器缺失
  • 随机数不安全:链上变量可预测
  • 访问控制/升级代理漏洞:initializer 调用次数、owner 控制不当
  • 习惯:用最新编译器、审计库(OpenZeppelin)、遵循 Checks-Effects-Interactions 模式

📖 详细讲解

重入攻击(Reentrancy)


攻击者通过 fallback/receive 函数在状态更新前重复调用合约。


防御方式


1. Checks-Effects-Interactions 模式:先检查、再更新状态、最后外部调用

2. ReentrancyGuard:使用互斥锁


其他常见漏洞


漏洞类型描述防御
整数溢出uint256 超过最大值回绕Solidity 0.8+ 自动检查
tx.origin 滥用钓鱼攻击使用 msg.sender
前端抢跑交易被抢先执行使用 Commit-Reveal
拒绝服务循环消耗过多 Gas限制循环次数

面试要点


• 能手写一个重入攻击案例

• Checks-Effects-Interactions 模式的具体应用

• 常用安全库(OpenZeppelin)的使用

💻 代码示例

重入攻击漏洞示例
// ❌ 有漏洞的合约
contract Vulnerable {
    mapping(address => uint256) public balances;

    function withdraw() public {
        uint256 amount = balances[msg.sender];
        // 危险:先转账,后更新状态
        (bool success, ) = msg.sender.call{value: amount}("");
        require(success);
        balances[msg.sender] = 0; // 攻击者可在此之前重复调用
    }
}

// ✅ 修复后的合约
contract Secure {
    mapping(address => uint256) public balances;

    function withdraw() public {
        uint256 amount = balances[msg.sender];
        // 先更新状态
        balances[msg.sender] = 0;
        // 后转账
        (bool success, ) = msg.sender.call{value: amount}("");
        require(success);
    }
}
💡
面试技巧:回答时先给出核心结论,再展开细节。如果有实际项目经验,一定要结合具体案例说明。