利用Crytic提升可升级合约安全性的全面指南

本文详细介绍了如何通过Crytic的17项升级性检查来避免可升级合约的常见陷阱,包括存储布局一致性、函数冲突检测和初始化模式验证等关键技术要点。

利用Crytic提升可升级合约安全性

可升级合约并不像你想象的那么安全。可升级架构可能存在缺陷,导致合约锁定、数据丢失或破坏事件恢复能力。每次合约升级都必须仔细审查以避免灾难性错误。最常见的delegatecall代理模式存在我们之前记录过的缺陷。

Crytic现在包含一套完整的17项可升级性检查,帮助您避免这些陷阱。

操作指南

审查可升级合约是一项复杂的底层任务,需要调查存储布局和内存中的函数组织。我们创建了支持可升级性的示例代币(crytic/upgradeability-demo)来演示具体步骤。这个简单演示库包含:

  • MyToken:简单代币的初始实现
  • Proxy:我们的代理合约

对Proxy的任何调用都会使用delegatecall在MyToken上执行其逻辑,而存储变量将保存在Proxy中。这是大多数可升级合约的标准设置。

假设这两个合约已部署在主网上,但MyToken代码已过时,需要更改功能。现在是时候使用MyTokenV2了!MyTokenV2代码与MyToken类似,只是移除了init()函数及其相关状态变量。

让我们使用Crytic来确保部署MyTokenV2不会引入新的安全风险。

配置

首先,在Crytic设置中配置可升级合约:

您可以配置:

  • 被升级的合约
  • 使用的代理
  • 合约的新版本

注意:(1)和(2)是可选的;Crytic将运行所有适用的检查。

例如,如果您只有可升级合约而没有代理或新版本,Crytic已经可以查找初始化模式中的缺陷。如果您有可升级合约和代理但没有新版本,Crytic可以查找实现和代理之间的函数冲突。如果有多个可升级合约或多个代理,可以配置任何适合您设置的组合。

配置完成后,可升级性检查将在每次提交和拉取请求时运行,类似于安全检查和单元测试。

Crytic的发现结果

有时Crytic会在您的可升级性代码中发现严重错误(哦不!)。我们在演示中构建了一个这样的问题。当Crytic发现安全问题时,显示如下:

was_init存储变量被移除,导致balances在MyToken和MyTokenV2中具有不同的存储偏移量,破坏了合约的存储布局。

这是一个常见错误,在具有许多合约和继承关系的复杂代码库中特别难以手动发现——但Crytic会为您捕捉这个问题!

Crytic还能发现什么?

Crytic将根据您的配置审查:

  • 升级和代理之间的存储布局一致性
  • 代理和实现之间的函数冲突
  • 正确的初始化模式
  • 变量使用的最佳实践

详细检查列表:

编号 检测内容 影响程度 需要代理 需要新版本
1 不应为常量的变量 X
2 函数ID冲突 X
3 函数遮蔽 X
4 缺少init函数调用
5 initializer()未被调用
6 多次调用初始化函数
7 v2中变量顺序错误 X X
8 代理中变量顺序错误 X X
9 具有初始值的状态变量
10 应为常量的变量 X
11 代理中的额外变量 X
12 v2中缺失的变量 X
13 v2中的额外变量 信息 X
14 未继承Initializable 信息
15 缺少Initializable 信息
16 必须调用的初始化函数 信息
17 缺少initializer() 信息

使用Crytic检查您的合约

除了发现90多个漏洞外,Crytic现在还可以检测可升级性代码中的缺陷。它是唯一能够深度保护您的代码库免受如此多问题影响的平台。如果您想避免灾难性错误,请在部署任何可升级合约之前使用Crytic。

有问题吗?加入我们的Slack频道(#crytic)或在Twitter上关注@CryticCI。

如果您喜欢这篇文章,请分享: Twitter | LinkedIn | GitHub | Mastodon | Hacker News

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计