Noções Básicas de Segurança
8 exemplos para você começar com segurança de programas - 5 básicos e 3 intermediários. Abrange o modelo de ameaça Solana, validação de conta, verificações de signatário e design fail-closed no Anchor 0.32.1.
Pré-requisitos
- Projeto Anchor 0.32.1 com
anchor-lang 0.32.1. - Leia Noções Básicas de CPI - muitos ataques cruzam fronteiras de programa.
anchor --version # 0.32.1Exemplos Básicos
1. Exigir um Signatário
Qualquer conta que move fundos ou muda autoridade deve assinar.
#[derive(Accounts)]
pub struct Withdraw<'info> {
#[account(mut)]
pub vault: Account<'info, Vault>,
pub authority: Signer<'info>,
}Signer<'info>falha se a conta não assinou a transação.- Verificações de signatário ausentes são o achado crítico mais comum.
- PDAs não podem ser
Signera menos que você useinvoke_signed.
Relacionado: Verificações de Signatário e Owner - padrões mais profundos
2. Validar Owner da Conta
Somente o programa proprietário deve interpretar dados da conta.
#[account(
mut,
constraint = vault.owner == program_id @ ErrorCode::InvalidOwner,
)]
pub vault: Account<'info, Vault>,Account<'info, T>do Anchor verifica owner == program_id automaticamente para seus tipos.AccountInfoeUncheckedAccountpulam isso - valide manualmente.- Ataques de confusão de tipo passam tipos de conta errados sem verificações de owner.
Relacionado: Ataques de Validação de Conta
3. Restringir Sementes PDA
PDAs devem ser derivadas com sementes canônicas e bump.
#[account(
seeds = [b"vault", authority.key().as_ref()],
bump = vault.bump,
)]
pub vault: Account<'info, Vault>,- Usuários não podem forjar PDAs sem as regras de semente do programa.
- Armazene bump no init para evitar custo de busca em runtime e ambiguidade de semente.
- Sementes erradas permitem que atacantes substituam seu próprio layout PDA.
Relacionado: Ataques de PDA e Semente
4. Usar Matemática Verificada
Quantidades de token e shares fazem overflow silencioso em builds release sem verificações.
let new_balance = old_balance
.checked_add(amount)
.ok_or(ErrorCode::Overflow)?;- Solana BPF usa aritmética com wrap por padrão em
+simples. - Use
checked_*,saturating_*ou intermediáriosu128. - Arredondamento favorece o protocolo, não o usuário, na divisão.
Relacionado: Aritmética e Overflow
5. Proteger Inicialização
Previna reinicialização de contas já inicializadas.
#[account(
init,
payer = payer,
space = 8 + Vault::INIT_SPACE,
)]
pub vault: Account<'info, Vault>,- Use
inituma vez, depoismutem instruções subsequentes. init_if_neededé perigoso sem guarda de flagis_initialized.- Atacante pode reexecutar init para resetar campos de admin.
Relacionado: Ataques de Reinicialização
Exemplos Intermediários
6. Validar ID de Programa CPI
Callees devem ser o programa que você espera, não um impostor.
let cpi_program = ctx.accounts.token_program.to_account_info();
require_keys_eq!(cpi_program.key(), anchor_spl::token::ID, ErrorCode::BadProgram);- Nunca confie em contas de programa fornecidas pelo usuário sem
require_keys_eq!. - SPL Token vs Token-2022 têm IDs de programa diferentes.
- Programa malicioso pode noop e retornar sucesso.
Relacionado: Riscos de CPI e Reentrância
7. Fechar Conta com Segurança
Drene lamports para destino e zere dados para prevenir revival.
#[account(
mut,
close = destination,
)]
pub temp: Account<'info, Temp>,- O atributo
closedo Anchor atribui lamports e zera discriminador. - Garanta que não há referências abertas ou closes duplicados na mesma tx.
- Fechar para conta controlada por atacante vaza rent se verificação de autoridade ausente.
8. Fail Closed em Oracle Obsoleto
Lógica dependente de preço deve rejeitar feeds obsoletos.
let price = feed
.get_price_no_older_than(clock.unix_timestamp, 60)
.ok_or(ErrorCode::StaleOracle)?;- Leituras de oráculo abertas permitem empréstimo contra preços desatualizados.
- Sempre combine com verificações de confiança para decisões de alto valor.
- Teste caminhos obsoletos no LiteSVM 0.6.x.
Relacionado: Oráculos - integração de feed
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.