在 Solana 开发这个高速交易与创新 DeFi 工具并存的快节奏世界里,代码中的一个微小疏忽就可能打开通往重大利用的大门。这样的事情正是在三月对 MetaDAO 发射台审计中发生的——一个涉及 Program Derived Addresses (PDA) 的细微漏洞,可能让攻击者抽走新铸造的代币。作为 Solana 安全公司 Accretion “Advent of Bugs”(漏洞降临)系列的一部分,这个第 1 天的披露把 PDA 冒充的问题摆在了台面上,提醒每一个区块链开发者务必再次核查他们的签名者验证逻辑。
如果你正深耕 Solana 智能合约,或者只是尝试在像这样的发射台上参与 meme 代币发行,继续往下看。我们会拆解出问题所在,逐步演示攻击流程,并分享关键教训以保护你的项目安全。无需博士学位——只要清晰、直接的见解,帮助你增强防御。
场景设定:发射台对 PDA 的信任
MetaDAO 的发射台旨在让代币发行流程平滑且去中心化,就像我们在 Solana 上看到爆火的 meme 币掉落一样。在初始化一次新发射时,程序会创建一个名为 launch_signer 的特殊账户。这不仅仅是任意账户——它是从发射的主键和固定种子("launch_signer")派生出的 PDA。PDA 是 Solana 用来创建没有私钥的“签名者”账户的方法,使用确定性种子确保它们仅受程序逻辑控制。
想法很简单:launch_signer PDA 作为新代币的铸币权(mint authority)。它对向指定账户铸造初始代币进行签名,从而启动发射。为此,程序使用 Solana 的 invoke_signed 函数,让程序能够通过提供的种子“代表”PDA进行签名。
但问题就出在这里。指令并没有明确验证所提供的 launch_signer 账户是否“确实匹配”期望的 PDA 地址。相反,代码信任将种子传入 invoke_signed 会处理一切。剧透一下:并没有。
漏洞揭露:冒充签名者
Accretion 的审计员发现了这一漏洞:程序将 launch_signer 标记为未校验账户(UncheckedAccount),意味着对其地址没有内建验证。这允许任意 Solana 账户被传入——前提是它在交易中作为顶层签名者且与铸币的 authority 匹配。
这为何重要?在 Solana 中,当你使用与种子不匹配的 invoke_signed 时,如果该账户已经对外层交易进行了签名,函数并不会失败。种子被忽略,攻击者的密钥对的真实签名接管了签名流程。砰——冒充成功。
这不是某个边缘的理论风险,而是直接通往代币铸造的后门。
攻击实战:在发射前窃取代币
想象你是个盯上热门 meme 代币发射的攻击者。以下是利用方法,按步骤说明:
准备陷阱:创建一个新的 mint 账户,并将你自己的密钥对(称作 K)设置为 mint authority。然后,创建一个由 K 拥有的代币账户来接收赃款。
触发初始化:调用
InitializeLaunch指令,传入 K 作为launch_signer。确保 K 对顶层交易进行签名——这很容易,因为你控制 K。铸造后门供给:程序欢然将代币铸到你 K 拥有的账户,以为它是通过 PDA 种子在签名。但实际上——是你的密钥对的签名在完成关键工作,而种子被置之不理。
掩盖痕迹:为避免触发警报,将大部分被盗代币转回,或将铸币权限交还给真实的 PDA,然后让发射按计划继续。你已经拿到非法分配,而项目方认为一切正常。
在 meme 代币的世界里,发射可能在数小时内推动数百万的资金,这种攻击可能在社区还未察觉前就抢走一大份额。这类隐蔽利用能把“飞向月球”变成“飞入攻击者的钱包”。
(如需查看标注出缺失校验的代码片段,请参见下方推文线程中的注释 Rust 代码。)
为什么会发生:关于 Solana 签名细节的快速入门
如果你对 PDA 不熟,简单把它们想象成由程序控制的“幽灵签名者”。它们由种子(比如 ["launch_signer", launch.key()])和 find_program_address 派生,确保只有程序能在 CPI(跨程序调用)中通过种子进行“签名”。
但 Solana 的灵活性是把双刃剑。invoke_signed 依赖种子来将 PDA 的地址从 ed25519 曲线中“抬升”出来,以便程序化签名。没有显式的地址校验(例如 require_keys_eq!(launch_signer.key(), expected_pda)),攻击者就能换上他们自己的签名者。该线程的第二张图展示了完整的指令流程,包括那个未被校验的 mint。
这是经典的“信任但要验证”——用代码的话,就是始终进行验证。
给 Solana 开发者和 Meme 代币构建者的教训
Accretion 的修复?很简单:添加一条校验,确保传入的 launch_signer 与派生出的 PDA 相匹配。这样就没有冒充的空间了。
对所有在 Solana 上构建的人——尤其是在 meme 代币和发射台这片“狂野西部”——更广泛的要点:
- 始终验证 PDA:使用
invoke_signed时,计算期望的 PDA 并断言它等于提供的账户。这既便宜又万无一失。 - 在可能的时候避免使用 UncheckedAccount:
UncheckedAccount提供了灵活性,但要与对签名者的显式校验配合使用。 - 早审计、频繁审计:正如线程所指出的,这个漏洞在初次审查时被漏过。像 Accretion 这样的公司能发现这些宝石——在下次发射前考虑请人审计。
- 测试边界情况:使用 Solana 的
solana-program-test等工具模拟攻击,以捕捉签名者不匹配的问题。
在由炒作推动价值往往快于代码审查的 meme 代币生态里,这些漏洞可以决定项目成败。MetaDAO 在审计后修补了这个问题,但类似故事会让社区保持警惕。
总结:安全是积累的,漏洞不必如此
“Advent of Bugs” 系列开了个好头,提醒我们 Solana 的速度不能成为马虎安全的借口。向 @r0bre 和 Accretion 团队致敬——他们的分享对追求安全、可扩展发射的开发者来说是金矿。
你在酝酿 Solana 项目吗?在评论里说说你的看法:有没有遇到过 PDA 的坑?你的常用修复是什么?如果你在 Meme Insider 审计 meme 代币,联系我们获取最新的安全发射资讯。
保持警惕——因为在区块链世界里,一个未校验的签名者就能引发千百个利用。