
一、先明确术语与适用范围
关键词中的“只能合约”通常指“智能合约”,即部署在区块链上、按代码规则执行的程序。本文讨论以太坊及 Solidity 合约的通用安全问题,不代表对任何具体项目的安全结论。
以太坊开发者文档强调,合约部署后的修复受到代码不可随意更改等条件限制。因此,安全检查应在设计阶段开始,而不是等程序上线后再补做。

二、公开调用不等于拥有操作权限
访问控制首先要回答:谁能执行哪些操作?OpenZeppelin 文档介绍了单一所有者与角色权限两类机制。前者适用于管理职责简单的场景,后者适合将不同职责分别授权。

检查时不能只看有没有权限修饰符,还要核对权限是否符合业务目的。例如,负责暂停服务的账户是否同时获得了不必要的其他管理权。角色数量多,也不自动意味着管理风险更低。
三、管理员本身也需要约束
OpenZeppelin 文档提醒,默认管理员具有较强的角色管理能力;所有权转移错误或放弃所有权,也可能影响后续管理。两步交接可要求接收方确认,多签则可让重要决定需要多方同意。
这些机制解决的问题不同:交接确认主要减少接收错误,多方批准主要减少单人决定的风险。选择时应分别考虑日常操作、人员离任和管理权限不可用等情况,不能把某一种机制当作全面保障。
四、校验条件必须来自明确的业务规则
以太坊开发者文档建议,通过条件检查与异常回退保护合约操作,并结合测试和独立审查检查代码。require 常用于输入、权限和状态前提检查,assert 用于内部不变量检查,revert 用于主动终止不符合条件的执行。
关键不是检查语句的数量,而是规则是否完整。开发前应明确哪些输入可以接受、哪些状态允许操作、哪些关系必须始终成立,再核对实现是否覆盖这些要求。
五、测试通过与审计完成意味着什么
测试通过,只说明已执行的检查没有发现问题;审计完成,也不等于合约不存在缺陷。独立审查应关注实现与业务规则是否一致,而不只是代码能否编译。
形式化验证同样存在适用边界:结论依赖所建立的模型、假设和性质,不能直接扩大为整个系统绝对安全。验收时应同时记录检查了什么,以及哪些内容不在检查范围内。
六、上线前应留下可核对的管理记录
上线准备可以围绕三个问题整理:实际部署的版本是否经过检查,当前权限是否与设计一致,未来变更由谁批准。权限交接、角色撤销和代码修改都应具有清楚的记录。
安全工作的目标不是获得一次性的“安全标签”,而是让代码规则、管理权限与后续变更持续保持一致。