Skip to main content

2 spl vuls

原文:Security of Solana Smart Contracts: Two Caveats of the SPL Associated Token Account | Sec3 Blog

1. 别用associated token account(ATA)当owner

如果不小心用ata当了你的token account owner,那你的token就没了,无法恢复。

#[allow(clippy::too many_arguments)]fn create_account(
from_account_index: IndexOfAccount,
to_account_index: IndexOfAccount,
to_address: &Address,
lamports: u64,
space: u64,
owner: &Pubkey,
signers: &HashSet<Pubkey>,
invoke_context: &InvokeContext,
transaction_context:&TransactionContext,
instruction_context: &InstructionContext,
) -> Result<()InstructionError> {

1.1. 分析

ata当了owner之后,用户就无法自己控制account了:无法修改account data

因为ata是PDA,没有对应的私钥来做签名

1.2. 修复

solana后来实现了一个叫RecoverNested的instruction来帮助恢复nested ATA,参考

If an ATA X is owned by another ATA Y, then X is called a nested ATA, and its tokens can be recovered by the RecoverNested instruction. The instruction will transfer all tokens in X to Y and close X.\n如果ata x被另一个ata y拥有,那x就是nested ata。可以用recoverNested instrution来恢复。这个操作会把所有x里的token转移给y,并关闭x

1.3. 注意事项

然而 recovernested无法恢复non-nested ata。\n也就是说:一个token account被一个ata own,但是这个token account不是ata,那就无法recover

2. 不能只通过owner和mint来验证ata

如果只通过owner和mint来验证ata,而不是用get_associated_token_address,那可能会有非法的token account通过检查

#[account(mut, 
constraint = vault_ata.owner == vault.key(),
constraint = vault_ata.mint == vault.mint
)]
pub vault_ata: Box<Account<'info, TokenAccount>>,

2.1. 分析

这里只验证了vault_ata owner是不是vault,以及vault_ata mint和 vault.mint一样。但是没有验证vault_ata是不是ata

所以攻击者可以构造一个token account(把owner设置成vault.key(),mint设置成vault.mint)\n就能通过检查了。

2.2. 修复

通过get_associated_token_address来验证ata

#[account(mut, 
address = get_associated_token_address(&vault.key(), &vault.mint)
)]
pub vault_ata: Box<Account<'info, TokenAccount>>,

\