文章讨论了Solana智能合约中的SPL Associated Token程序的两个重要注意事项:不要将关联Token账户设置为其他Token账户的所有者,以及在验证关联Token账户时,不能仅依赖所有者和铸造信息。文中提供了相关的代码示例以及潜在的安全问题。
SPL关联代币程序在Solana智能合约中被频繁使用。我们在之前的一篇文章中回顾了其技术细节。在本文中,我们着重讨论Sec3核心团队了解到的使用关联代币账户的两个重要注意事项。
如果错误地将关联代币账户设置为代币账户的所有者,你可能会丢失所有代币,并且这些代币可能无法恢复。
使用系统程序创建新账户时,可以将任何Pubkey作为新账户的所有者传入:
查看 源代码
但是,如果你错误地将一个关联代币账户(ATA)传入作为所有者,那么你将失去对该账户的控制权,也就是说,无法修改账户数据。
原因在于ATA是一个PDA(即程序派生账户),并没有相应的私钥来进行签名。
这个问题已经发生在一些用户身上(例如, https://github.com/solana-labs/solana-program-library/pull/288 9),而Solana实施了一条名为RecoverNested的指令,以帮助恢复嵌套的ATA(查看详细信息)。
如果一个ATA X是由另一个ATA Y拥有,那么X被称为嵌套的ATA,其代币可以通过RecoverNested指令恢复。该指令将X中所有代币转账到Y,并关闭X。
重要的是,截至2022年9月,RecoverNested指令不恢复非嵌套的ATA。也就是说,如果一个代币账户由一个ATA拥有,但该代币账户本身不是ATA,那么它不能被恢复。
如果仅通过所有者/铸造来验证关联代币账户,而不是使用get_associated_token_address,可能会允许意想不到的代币账户传入,这可能会干扰你的协议。
仅通过所有者和铸造来验证关联代币账户是不够的。例如,在Anchor账户验证中,使用以下约束(而不是_get_associated_tokenaddress):
#[account(mut,
constraint = vault_ata.owner == vault.key(),
constraint = vault_ata.mint == vault.mint
)]
pub vault_ata: Box<Account<'info, TokenAccount>>,
上述代码仅验证vault_ata的所有者是vault,并且它与vault.mint具有相同的铸造,但是vault_ata可能根本不是ATA。
攻击者可以传入任意代币账户(将其owner和mint分别设置为vault.key()和vault.mint),并通过验证。根据协议逻辑,传入的伪造ATA可能会导致安全问题。
要验证ATA,请使用_get_associated_tokenaddress:
#[account(mut,
address = get_associated_token_address(&vault.key(), &vault.mint)
)]
pub vault_ata: Box<Account<'info, TokenAccount>>,
- 原文链接: sec3.dev/blog/two-caveat...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!