跳转至主要内容

智能合约安全性准则

Solidity
智能合同
安全性。
中级
Trailofbits
2020年9月6日
7 分钟阅读

遵循这些高级建议,构建更安全的智能合约。

设计指南

编写代码之前,务必先讨论行智能合约的设计。

文档和规范

文档可以在不同级别编写,在执行合约时应进行更新:

链上计算与链下计算

  • **尽可能将代码放在链下。**保持较小的链上层。 用链下代码预处理数据,从而简化链上验证。 是否需要已排序列表? 在链下对列表进行排序,然后在链上只检查其顺序。

可升级性

我们在我们的博文opens in a new tab中讨论了不同的可升级性解决方案。 在编写任何代码之前,请慎重选择是否支持可升级性。 该决定将影响你如何构建你的代码。 一般来说,我们建议:

  • **优先选择合约迁移opens in a new tab,而非可升级性。**迁移系统与可升级系统相比,具有许多相同优点,但没有其缺点。
  • **使用数据分离模式,而非 delegatecallproxy 模式。**如果你的项目有明确的抽象分离,使用数据分离实现的可升级性将仅需少量调整。 delegatecallproxy需要EVM专业知识,并且非常容易出错。
  • **在部署前记录迁移/升级程序。**如果你在毫无指导的情况下,必须顶着压力做出反应,就可能会犯错。 提前写好要遵循的程序。 其中应包括:
    • 启动新的智能合约的调用
    • 密钥存放在哪里以及如何获取它们
    • 如何检查部署! 开发和测试部署后的脚本。

实施指南

**力求简洁。**始终使用最简单的解决方案来实现你的目的。 所有的团队成员都应当能够理解解决方案。

函数组合

使用便于检查的代码库架构, 避免选择不利于正确性验证的架构。

  • 拆分系统逻辑,既可以通过多个合约,也可以将相似的函数分组(例如,身份验证、算术运算……)。
  • **编写目的明确的小函数。**这样便于审查,也可以对单个组件进行测试。

继承

  • **保持继承的可管理性。**继承可用于划分逻辑,但是,你的项目应旨在尽量减小继承树的深度和宽度。
  • **使用 Slither 的 inheritance printeropens in a new tab 检查合约的层级结构。**inheritance printer 将帮助你审查层级结构的大小。

事件

  • **记录所有关键操作。**事件将有助于在开发期间调试合约,并在部署后监控合约。

避免已知陷阱

依赖项

  • **使用经过充分测试的库。**从经过充分测试的库导入代码会降低你编写错误代码的可能性。 如果你想编写 ERC20 合约,请使用 OpenZeppelinopens in a new tab
  • **使用依赖项管理器;避免复制粘贴代码。**如果你依赖外部源,则必须使其与原始源保持同步。

测试和验证

Solidity

  • **优先使用 Solidity 0.5,而非 0.4 和 0.6。**我们认为,与 0.4 版本相比,Solidity 0.5 更安全,并且内置了更好的实践。 Solidity 0.6对于发布级产品而言过于不稳定,还需要时间才能趋于成熟。
  • **使用稳定版本进行编译;使用最新版本检查警告。**确保你的代码在最新编译器版本下没有报告任何问题。 然而,Solidity 的发布周期很快,且有过编译器漏洞的历史,因此我们不建议使用最新版本进行部署(请参阅 Slither 的 solc 版本建议opens in a new tab)。
  • **不要使用内联汇编。**汇编需要 EVM 专业知识。 如果你没有_精通_黄皮书,请不要编写 EVM 代码。

部署指南

合约开发和部署完成后:

  • **监控你的合约。**关注日志,并准备好在合约或钱包受损时做出反应。
  • **将你的联系信息添加到 blockchain-security-contactsopens in a new tab。**如果发现安全漏洞,此列表可帮助第三方联系你。
  • **保护特权用户的钱包安全。**如果你将密钥存储在硬件钱包中,请遵循我们的最佳实践opens in a new tab
  • **制定事件响应计划。**要考虑到你的智能合约可能被攻击。 即使合约本身没有错误,攻击者也可能有机会控制合约拥有者的密钥。

页面最后更新: 2025年9月30日

本教程对你有帮助吗?