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

本文介绍了Trail of Bits开发的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 设计