Q11 · 智能合约与 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);
}
}面试技巧:回答时先给出核心结论,再展开细节。如果有实际项目经验,一定要结合具体案例说明。