0. 回顾
- 保护 Solana 生态系统 (1) — Hello Solana
- 保护 Solana 生态系统 (2) — 程序间调用
- 保护 Solana 生态系统 (3) — 程序升级
- 保护 Solana 生态系统 (4) — 账户验证
- 保护 Solana 生态系统 (5) — 多签
- 保护 Solana 生态系统 (6) — 多签2
1. 概述
在上一篇 博客 中,我们介绍了通用多签的实现。在本文中,我们将讨论另一个安全问题 — 类型混淆。
2. 反序列化/序列化
在 Solana 中,程序状态存储在账户中。类型混淆问题在账户的反序列化/序列化过程中出现。程序的逻辑通常依赖于数据结构。然而,程序在反序列化/序列化过程中可能没有正确检查账户的类型。这可能被攻击者滥用,导致意外损失。
3. 代码审查 (类型混淆)
接下来,我们将通过一个简单的程序来说明类型混淆的问题。您可以在 此处 找到测试代码。

在测试程序中,我们实现了两个数据结构,一个是 User,另一个是 Metadata。它们都记录了一个账户(不同的账户)的公钥。

该程序有三个不同的指令。InitializeUser 指令用于创建 User 账户并设置一个授权账户(即 authority)。类似地,InitializeMeta 指令用于创建 MetaData 账户并设置一个普通账户(即 account)。Test 指令演示了攻击者可以绕过程序的验证逻辑,并利用控制的 MetaData 进行攻击。

让我们一步步分析 Test() 指令。程序确保传入的 User 账户的所有者是程序本身(第 86 - 89 行)。反序列化后(第 92 行),程序比较传入的 authority 账户的公钥与存储在 User 账户中的公钥。如果它们不相等,程序将回滚(第 93 - 96 行)。最后的检查是确保 authority 账户已签署交易。然而,如果攻击者传入受控的 Metadata 账户,所有检查都可以绕过。原因是程序没有检查账户的类型。它接收一个字节数组并直接将其反序列化为程序中定义的各种类型的结构体。
我们部署了测试程序进行进一步测试,可以在 此链接 找到。
3.1 发送交易
部署程序后,我们编写脚本按顺序调用程序提供的三个指令。
我们首先调用 InitializeUser 和 InitializeMeta。请注意,我们将我们自己的公钥设置为 Metadata 账户中存储的 account 账户。

在 test() 函数中,我们将 Metadata 账户作为 User 账户,将我们自己的账户作为 authority_info(第 347 - 348 行)。程序使用 User 结构体反序列化 Metadata,所有检查都可以绕过。

我们发送了交易,可以在 这里 找到。程序返回成功,这意味着我们成功通过了未经检查的账户类型的检查。
4. 总结
在本文中,我们介绍了 Solana 中的类型混淆问题。有许多方法可以避免这个问题。例如,我们可以添加一个属性来记录结构体中账户的类型,并且程序在读取/写入传入账户之前应始终检查类型属性。请继续关注,我们将在接下来的博文中分享更多内容。
阅读本系列的其他文章:
- 保护 Solana 生态系统 (1) — Hello Solana
- 保护 Solana 生态系统 (2) — 程序间调用
- 保护 Solana 生态系统 (3) — 程序升级
- 保护 Solana 生态系统 (4) — 账户验证
- 保护 Solana 生态系统 (5) — 多签
- 保护 Solana 生态系统 (6) — 多签2
关于 BlockSec
BlockSec 是一家开创性的区块链安全公司,由一群全球杰出的安全专家于 2021 年创立。公司致力于提升新兴 Web3 世界的安全性和可用性,以促进其大规模采用。为此,BlockSec 提供智能合约和 EVM 链 安全审计 服务,用于安全开发和主动阻止威胁的 Phalcon 平台,用于资金追踪和调查的 MetaSleuth 平台,以及供 Web3 构建者在加密世界高效冲浪的 MetaSuites 扩展。
迄今为止,公司已为 MetaMask、Uniswap Foundation、Compound、Forta 和 PancakeSwap 等 300 多家尊贵客户提供服务,并从 Matrix Partners、Vitalbridge Capital 和 Fenbushi Capital 等知名投资者那里获得了两轮数千万美元的融资。



