本文总结了Solana链上程序开发的五大安全隐患,包括:缺少签名者检查、账户所有权未验证、不安全的跨程序调用(CPI)模式、计算中的整数溢出以及PDA种子冲突。
在 Solana 上构建?以下是数百万美元漏洞背后的关键失败之处:
is_signer 检查,让任何人都可以冒充权威此清单涵盖 8 个领域中的 45 项安全检查。在审计之前、开发期间以及作为发布前的关卡使用它。
完整安全清单
45+ 个漏洞、攻击模式和缓解措施 — 每一个都带有技术细节和代码示例。专为审计员和具有安全意识的开发团队构建。
Solana 的编程模型与基于 EVM 的链根本不同。当以太坊开发者担心重入和存储冲突时,Solana 开发者面临着一系列独特的挑战:
风险很高:
此清单是从 50 多份 Solana 审计报告和每个主要的 Solana 漏洞中提炼出来的。无论你使用 Anchor 还是原生 Solana 构建,本指南都涵盖了重要的漏洞。
此清单分为八个关键领域:
每个检查都包括严重性评级(严重/高/中)以及我们交互式清单中详细说明的链接。
Wormhole 漏洞(3.2 亿美元)的发生是因为程序在没有验证 is_signer 标志的情况下检查了 pubkey。身份验证失败是 Solana 漏洞的头号原因。
constraint = config.admin == admin.key() 而不是手动检查is_signer — 仅检查 pubkey 是不够的;任何人都可以传递任何 pubkeySigner<'info> — 此类型会自动验证签名Account<'info, T> — Anchor 会自动验证类型化账户的所有权init 约束 — 防止重新初始化program_data.upgrade_authority_address仅检查 admin.key() == expected_key 而没有 Signer<'info> 的函数
没有所有权约束的 AccountInfo<'info> 或 UncheckedAccount
单步权限转移
任何人都可以调用的初始化
Solana 的账户模型意味着状态可以以以太坊开发者意想不到的方式进行操纵。陈旧的数据、重复的账户和不正确的关闭都会产生漏洞。
zero_init 参数 — 当大小在同一事务中减小后增加时,设置为 true.reload()close 约束可以做到这一点constraint = account_a.key() != account_b.key()bump 约束 — 自动规范派生具有硬编码 zero_init = false 的 realloc
CPI 之后访问的账户数据没有重新加载
仅转移 lamport(没有数据归零)的关闭账户
仅具有静态 seed(没有用户区分)的 PDA
CPI 功能强大但危险。将签名者转发到不受信任的程序可能会导致钱包被盗或所有权重新分配。“盗取钱包”攻击可能会永久锁定用户资金。
Program<'info, T> — Anchor 会自动验证程序 ID使用用户提供的程序账户的 invoke()
传递给第三方程序 CPI 的用户钱包 (Signer<'info>)
具有不受约束的根账户的验证链
接收签名者的 CPI 之后没有所有权检查
Rust 的 release 构建版本(Solana 使用的版本)默认不检查整数溢出。单个溢出可能导致攻击者铸造无限 Token 或耗尽协议。
checked_add、checked_sub、checked_mul、checked_divoverflow-checks = true(a * b) / c 而不是 (a / c) * btry_from — u64::try_from(value) 而不是 value as u64as — 静默截断很危险u64 值上的直接算术运算符 (+、-、*、/)
对用户提供或计算的值进行 as 转换
没有零检查的除法
收费计算中除法后的乘法
Token 处理需要仔细验证。错误的 mint、丢失的权限以及收费转移 Token 都会产生漏洞。
token_interface — 为了 Token-2022 兼容性transfer_checked — 验证小数,适用于两个程序Interface<'info, TokenInterface> 与 token_interface::transfer_checked 结合使用init_if_needed — ATA 可以由任何人预先创建init — 攻击者可以抢先并进行 DoS 攻击token_account.mint == expected_minttoken_account.owner == expected_owner关联 Token 账户上的 init 约束
没有 mint 验证的 Token 转移
将 token::transfer 与 Interface<'info, TokenInterface> 结合使用
Token-2022 引入了强大的扩展,可以从根本上改变 Token 行为。没有考虑到这些功能的程序可能会被利用。
default_account_state 扩展transfer_checked — 自动处理费用计算没有检查 Token-2022 扩展
假设转移金额等于收到的金额
没有为转移 Hook 预算 CU
接受具有永久委托的 Token 存款
细微的错误和 Rust 语法错误可能会导致严重的漏洞。这些问题通常会通过代码审查,但在生产中会失败。
vec![value; count] — 而不是 vec![count]Account<'info, T> 执行此操作address = sysvar::xxx::ID 约束b"user_vault" 与 b"admin_vault"交易上没有滑点保护
直接将 lamport 转移到用户提供的地址
vec![N] 意为 vec![0; N]
没有验证逻辑的 UncheckedAccount
这些问题需要对 Solana 内部原理有更深入的了解,即使是经验丰富的开发人员也经常忽略。
跨关闭账户的 CPI 持有的引用
没有明确目的的临时所有者更改
无限制的向量或循环
没有位置验证的 Ed25519 签名
此清单是一个起点,而不是终点。Solana 安全性需要:
我们的团队已审计了 30 多个 Solana 协议,在关键漏洞变成漏洞之前发现并修复了它们。
我们提供什么:
- 原文链接: zealynx.io/blogs/solana-...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!