Propriedade e Permissões da Conta
A regra de o proprietário escreve é o invariante de segurança do Solana: apenas o programa proprietário de uma conta pode modificar seus data (e certos metadados). Signatários autorizam transferências de lamports; proprietários autorizam mutações de dados.
Receita
#[derive(Accounts)]
pub struct SecureUpdate<'info> {
#[account(
mut,
has_one = authority @ MyError::Unauthorized,
constraint = data.is_active @ MyError::Inactive,
)]
pub data: Account<'info, MyData>,
pub authority: Signer<'info>,
}Quando usar isso:
- Toda instrução que muta contas de propriedade do programa
- Auditoria de programas para verificações de signatário ou proprietário ausentes
- Projetando fluxos de CPI onde o chamado deve confiar nas contas passadas
- Entendendo por que
UncheckedAccounté perigoso por padrão
Exemplo de Trabalho
use anchor_lang::prelude::*;
#[account]
pub struct MyData {
pub authority: Pubkey,
pub is_active: bool,
pub balance: u64,
}
#[program]
pub mod permissions {
use super::*;
pub fn update_balance(ctx: Context<UpdateBalance>, new_balance: u64) -> Result<()> {
ctx.accounts.data.balance = new_balance;
Ok(())
}
pub fn steal_attempt(ctx: Context<StealAttempt>) -> Result<()> {
// ISSO FALHA em tempo de execução - o chamador não é o proprietário da conta vítima
Ok(())
}
}
#[derive(Accounts)]
pub struct UpdateBalance<'info> {
#[account(mut, has_one = authority)]
pub data: Account<'info, MyData>,
pub authority: Signer<'info>,
}
#[derive(Accounts)]
pub struct StealAttempt<'info> {
#[account(mut)]
pub data: Account<'info, MyData>, // Anchor verifica proprietário == programa
pub attacker: Signer<'info>,
}O que isso demonstra:
Account<'info, MyData>verifica proprietário == este programahas_one = authorityvincula direitos de mutação a uma pubkey armazenada- O atacante não pode passar a conta de outro usuário, a menos que seja a autoridade
Análise Detalhada
Camadas de Permissão
| Verificação | Imposta Por | Propósito |
|---|---|---|
| Programa proprietário | Tempo de execução | Apenas o proprietário escreve dados |
| Signatário | Tempo de execução | Assinatura Ed25519 presente |
has_one / constraint | Anchor | Autenticação em nível de aplicativo |
| Flags de metadados da conta | Tempo de execução | Gravável vs. somente leitura |
Permissões de CPI
- O chamador passa contas para o chamado; o chamado revalida
- O programa proprietário pode usar CPI para delegar transferências de tokens (SPL)
invoke_signedpermite que programas assinem por PDAs
Armadilhas
- UncheckedAccount sem restrições - substituição arbitrária de conta. Correção: adicione verificações de proprietário, seeds ou
has_one. - Signer != authority - o usuário assina, mas não é a autoridade armazenada. Correção:
has_one = authorityemSigner. - Flag gravável em contas não autorizadas - o tempo de execução pode rejeitar ou o programa proprietário deve permitir. Correção: marque apenas contas graváveis que seu programa possui e pretende mutar.
- Falta de
mutem contas que mudam - operação silenciosa sem efeito ou erro de compilação. Correção:#[account(mut)]em toda conta alterada. - Confundir proprietário do token com autoridade da conta - SPL tem proprietário e delegado separados. Correção: use restrições SPL ou CPI corretamente.
Alternativas
| Alternativa | Usar Quando | Não Usar Quando |
|---|---|---|
has_one | Única pubkey de autoridade nos dados | Multi-assinatura (use restrição personalizada) |
seeds + bump | Autoridade PDA | Carteira do usuário é a autoridade |
Expressões constraint | Regras booleanas complexas | Correspondência simples de pubkey (use has_one) |
require! manual | Verificações dinâmicas | Verificações de layout estático (prefira restrições) |
FAQs
Qual é a regra de o proprietário escreve?
Apenas o programa listado em account.owner pode modificar o buffer de dados da conta.
Um signatário pode mutar qualquer conta?
Não. Signatários autorizam transações; escritas de dados ainda requerem lógica do programa proprietário na instrução.
O que has_one verifica?
Um campo pubkey dentro dos dados da conta corresponde à pubkey de outra conta na struct.
Programas podem mudar o proprietário da conta?
O programa proprietário pode chamar o assign do System Program para transferir a propriedade - raro e perigoso se mal utilizado.
Por que usar Signer vs UncheckedAccount para autoridade?
Signer prova que assinou a transação. UncheckedAccount não - deve adicionar verificação manual de signatário.
O que é uma vulnerabilidade comum de drenagem?
A verificação ausente de proprietário/autoridade permite que o atacante passe a conta da vítima com a flag gravável.
Contas somente leitura precisam de signatário?
Não, a menos que sua lógica exija prova de identidade para caminhos de leitura (incomum).
Como PDAs se encaixam nas permissões?
O programa assina via invoke_signed com seeds; nenhum signatário humano é necessário para lógica de propriedade de PDA.
Dois signatários podem co-autorizar?
Sim. Passe várias contas Signer e valide ambas nas restrições.
Qual o impacto da tabela de lookup de endereços?
ALTs mudam como os endereços são referenciados, não as regras de propriedade.
O Anchor verifica o proprietário da conta de token?
Restrições InterfaceAccount / token verificam a propriedade do programa SPL Token.
Como auditar permissões?
Liste cada conta mut; rastreie as verificações de signatário e proprietário necessárias por instrução.
Relacionado
- Contas do Sistema vs. Contas de Programa - quem possui o quê
- Estado de Propriedade do Programa - design de conta de estado
- Noções Básicas do Modelo de Conta - exemplos de restrições
Versões da Stack: Esta página foi escrita para Agave 4.1.1, Solana CLI 3.0.10, Anchor 0.32.1, anchor-lang 0.32.1, Rust 1.91.1, @solana/kit 7.0.0, Surfpool 0.12.0, e LiteSVM 0.6.x.