autorenew
漏洞来袭 #3:可选账户如何让用户在 Solana 交易中绕过手续费

漏洞来袭 #3:可选账户如何让用户在 Solana 交易中绕过手续费

你有没有觉得你的智能合约刀枪不入,直到一次审计暴露出一个狡猾的漏洞?这正是我们在 Accretion 审计的这个 Solana DeFi 项目中遇到的情况。欢迎来到 ​漏洞来袭 #3​,在这里我们深入探讨可选账户、良好初衷以及 Solana 状态机细节如何把一个收费机制变成免费的嘉年华。

如果你正全身心投入构建或审计 Solana 程序,这篇对你很有帮助。我们会拆解问题、说明为何它会漏测,以及那种既安全又不膨胀指令大小的优雅修复方案。不需要博士学位——只有清晰、实用的见解,帮助你提升区块链实战能力。

场景设定:手续费、Swap 与来自另一个程序的协助

想象一下:你在 Solana 上有一个很酷的 DeFi swap 协议。为了维持运行,你对每笔交易收取少量手续费。听起来很简单,对吧?但扭曲在这里——大部分用户并不会直接调用你的核心 swap 指令。相反,他们通过前端或 SDK 走到一个单独的“fee program”。这个 fee program 收取费用,然后通过 Cross-Program Invocation (CPI)—Solana 允许一个程序调用另一个程序的方式—把调用转给你的主 swap 逻辑。

为什么要多这一步?为了效率和模块化。fee program 负责付款、日志或其他职责,而你的 swap 保持精简。但为了避免重复收费(被收两次),主 swap 指令将其手续费账户标记为​​可选​​。如果提供了,就收费;如果没有(比如在 CPI 流程中),就跳过继续执行。

听起来很聪明。直到并不聪明为止。

漏洞:可选账户让无费 swap 成为可能

在我们的审计中,我们发现了阿基里斯之踵:任何人都可以直接调用主 swap 指令,完全绕过 fee program。只要简单地不提供手续费账户,用户就可以规避收费。砰——给精明(或恶意)的交易者免费 swap。

这不是菜鸟错误。开发团队测试了典型路径:SDK 流和网站交互,那些场景下 fee program 担任守门人。直接调用?很少被测试,尤其在 DeFi 中抽象层掩盖了底层程序细节。此外,Solana 的指令大小限制(约 1,232 字节)让开发者对额外账户顾虑重重,所以可选账户看起来像是个不错的折衷。

但在区块链世界里,“看起来不错”是不够的。一个被忽视的向量,你的协议经济就会崩塌。严重度可能是中低?也许——但在高频 swap 场景下,那就是实打实的收入风险。

为什么难以处理:平衡意图、大小与安全

把这件事做对并不简单。你需要:

  • 让直接调用的用户支付手续费(强制要求该账户)。
  • 让来自 fee program 的 CPI 用户跳过重复计费。
  • 不要膨胀指令——额外账户会增加 compute units 并触及大小上限。

来自不受信任程序的任意 CPI?噩梦。并且要测试每一种边缘情况?耗时又费力。

根源在于:Solana 程序是无状态的机器,响应指令。没有明确检查,“可选”就变成了“可跳过”——意图不会自我强制执行。

修复方案:PDA、签名者与正确的 CPI 验证

解决办法?利用 Solana 的 Program-Derived Addresses (PDAs) 做为来源的加密证明。以下是我们审阅代码的要点:

在 fee program 中:

  • 从固定字符串如 "cpi_authority" 推导出一个 PDA seed。
  • 用这个 PDA 作为 authority 对主 swap 发起 CPI 签名。
  • 在指令中把该 PDA 作为 signer 账户传入。

在主 swap 程序中:

  • 期待接收到作为 CPI 授权者的 PDA 地址。
  • 验证提供的 signer 是否匹配:如果 signer.key() != expected,强制要求手续费账户(unwrap 它以确保存在并收取费用)。
  • 为安全起见,在检查后对手续费账户执行 unwrap——Solana 的 Rust SDK 让这类强制变得轻而易举。

这样一来:

  • 直接调用会在签名者检查上失败,从而被迫收取手续费。
  • 来自 fee program 的合法 CPI 会通过检查,使可选行为得以保留。
  • 无需额外账户;PDA 同时充当证明。

这是 Solana 安全原语的一堂示范课:用 PDAs 做确定性、由程序控制的密钥;用 signers 验证调用意图;用 unwrap 获得运行时保证。

想看示例吗?查看下面带注释的代码片段,重点行已标注。

显示 Solana Rust 代码片段,演示用 PDA 对 fee program 的 CPI 进行签名,以及主 swap 用 unwrap 强制收费的验证流程

给 Solana 构建者的教训:测试超越“顺利路径”

这个漏洞强调了一条黄金法则:功能与正确性不同。一定要审计​​绕过向量​​,尤其是在代币流或经济模型中。像我们在 Accretion 做的审计可以及早发现这些问题。

专业建议:

  • 对程序间信任尽量使用 PDAs。
  • 通过 signer 检查把可选项做成​​条件性的​​。
  • 在测试中模拟直接调用——像 Anchor's test framework 这样的工具在这方面很有用。
  • 还有,务必再确认那次 unwrap;它是你的安全网。

如果你在审计或构建 Solana 项目,给 @r0bre 发私信——我们在招募优秀人才,也喜欢一起钻这些问题。

鸣谢 @brymko 的敏锐发现。你遇到过最离谱的“可选”漏洞是什么?在下方回复分享。

保护好自己——漏洞会像沉积物一样慢慢积累,如果放任不管。

​此文灵感来自 Accretion 的真实审计。想看更多 Solana 安全深度解析,关注 Meme Insider 获取关于 meme token、DeFi 攻防和区块链知识的最新内容。​

你可能感兴趣