使用Crytic提升可升级合约安全性的17项关键检查

本文详细介绍了如何利用Crytic的17项升级性检查来发现可升级合约中的存储布局不一致、函数冲突等安全隐患,避免合约锁定、数据丢失等灾难性错误,确保智能合约升级过程的安全性。

使用Crytic让可升级合约更安全

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

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

操作指南

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

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

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

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

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

配置

首先,告诉Crytic关于您的可升级合约。转到您的Crytic设置并找到此面板:

在这里您可以配置:

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

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

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

回到MyToken,我们有这三个合约:

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

Crytic的发现

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

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

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

Crytic还能发现什么?

Crytic将审查(取决于您的配置):

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

以下是详细的检查列表:

编号 检测内容 影响 需要代理 需要新版本
1 不应为常量的变量 X
2 函数ID冲突 X
3 函数遮蔽 X
4 缺少init函数调用
5 initializer()未被调用
6 Init函数被多次调用
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 设计