安全基础
Solidity 常见安全风险和注意事项。
发布于 2026年5月30日0 views
Solidity 合约部署后运行在链上,资产和权限都是真实的,所以安全比普通后端代码更重要。
权限控制
敏感函数必须做权限检查。
address public owner;
modifier onlyOwner() {
require(msg.sender == owner, "Not owner");
_;
}
function setFee(uint256 fee) external onlyOwner {
// update fee
}没有权限控制的管理函数,很容易被任何人调用。
重入攻击
重入攻击通常发生在合约向外部地址转账时,外部合约又回调回来重复执行。
危险模式:
function withdraw() external {
uint256 amount = balances[msg.sender];
(bool ok, ) = msg.sender.call{value: amount}("");
require(ok, "Transfer failed");
balances[msg.sender] = 0;
}更安全的顺序是:先改状态,再外部调用。
function withdraw() external {
uint256 amount = balances[msg.sender];
balances[msg.sender] = 0;
(bool ok, ) = msg.sender.call{value: amount}("");
require(ok, "Transfer failed");
}外部调用
外部调用要谨慎:
- 对方合约可能失败。
- 对方合约可能恶意回调。
- 调用结果必须检查。
(bool success, ) = target.call(data);
require(success, "Call failed");整数溢出
Solidity 0.8+ 默认会检查整数溢出。
但如果使用 unchecked,要自己保证安全:
unchecked {
count += 1;
}只有在明确需要省 gas 且不会溢出时才使用。
常见建议
- 管理函数加权限。
- 先改状态,再外部调用。
- 检查外部调用返回值。
- 重要操作 emit event。
- 不要相信外部输入。
- 升级合约要保持存储布局。
- 上线前做测试和审计。
总结
Solidity 安全的核心是:权限要明确,外部调用要谨慎,状态更新顺序要正确。合约一旦上线,错误成本通常比普通应用高很多。