Futuros
Aceda a centenas de contratos perpétuos
TradFi
Ouro
Plataforma de ativos tradicionais globais
Opções
Hot
Negoceie Opções Vanilla ao estilo europeu
Conta Unificada
Maximize a eficiência do seu capital
Negociação de demonstração
Introdução à negociação de futuros
Prepare-se para a sua negociação de futuros
Eventos de futuros
Participe em eventos para recompensas
Negociação de demonstração
Utilize fundos virtuais para experimentar uma negociação sem riscos
Lançamento
CandyDrop
Recolher doces para ganhar airdrops
Launchpool
Faça staking rapidamente, ganhe potenciais novos tokens
HODLer Airdrop
Detenha GT e obtenha airdrops maciços de graça
Launchpad
Chegue cedo ao próximo grande projeto de tokens
Pontos Alpha
Negoceie ativos on-chain para airdrops
Pontos de futuros
Ganhe pontos de futuros e receba recompensas de airdrop
Investimento
Simple Earn
Ganhe juros com tokens inativos
Investimento automático
Invista automaticamente de forma regular.
Investimento Duplo
Aproveite a volatilidade do mercado
Soft Staking
Ganhe recompensas com staking flexível
Empréstimo de criptomoedas
0 Fees
Dê em garantia uma criptomoeda para pedir outra emprestada
Centro de empréstimos
Centro de empréstimos integrado
Centro de Património VIP
Aumento de património premium
Gestão de património privado
Alocação de ativos premium
Fundo Quant
Estratégias quant de topo
Staking
Faça staking de criptomoedas para ganhar em produtos PoS
Alavancagem inteligente
New
Alavancagem sem liquidação
Cunhagem de GUSD
Cunhe GUSD para retornos RWA
Vulnerabilidade de Reentrancy: Como Identificar, Explorar e Prevenir
No mundo dos contratos inteligentes, reentrancy é considerada uma das vulnerabilidades mais perigosas. Este artigo irá ajudá-lo não apenas a entender claramente o que é um ataque de reentrancy, mas também a como preveni-lo de forma eficaz. Desde técnicas básicas até soluções avançadas, exploraremos maneiras de proteger todo o seu projeto.
Como Funciona a Reentrancy: Mecanismo Básico de Ataque
Para entender a reentrancy, primeiro precisamos compreender o conceito fundamental: um contrato inteligente pode chamar outro contrato, e nesse momento, o segundo contrato pode fazer uma chamada de volta ao primeiro enquanto ainda está em execução.
Imagine que você tem dois contratos: ContractA contendo 10 Ether e ContractB que enviou 1 Ether para ele. Quando ContractB chama a função de saque, ela verifica se há saldo suficiente. Se houver, o Ether é enviado de volta para ContractB. Aqui, se não houver medidas de proteção adequadas, esse é o ponto fraco que um atacante pode explorar.
Em um ataque de reentrancy típico, o atacante precisará de duas funções: attack() para iniciar o ataque, e fallback() para fazer chamadas recursivas. A função fallback é uma função especial em Solidity — ela não tem nome, nem parâmetros, e é chamada automaticamente sempre que Ether é enviado ao contrato sem dados adicionais.
Passo a Passo do Ataque de Reentrancy
Acompanhe o processo de ataque passo a passo. O atacante chama a função attack() do seu contrato. Dentro dela, ela chama a função withdraw() de ContractA.
Quando ContractA recebe essa chamada, verifica se ContractB tem saldo maior que zero. Como há 1 Ether, a verificação passa. Então, ContractA envia 1 Ether de volta para ContractB, ativando sua função fallback. Nesse momento, ContractA fica com 9 Ether, mas o mais importante: o saldo de ContractB no livro-razão de ContractA ainda não foi atualizado para zero.
Esse é o problema: a função fallback chama novamente withdraw() de ContractA. ContractA verifica novamente o saldo de ContractB — que ainda é 1 Ether! Por quê? Porque a linha balance[msg.sender] = 0 nunca foi executada, pois está após o envio de Ether.
Esse ciclo se repete: chamada de withdraw → verificação do saldo (ainda > 0) → envio de Ether → ativação do fallback → chamada recursiva de withdraw… até que todo o Ether de ContractA seja drenado.
Análise do Código: Quando a Reentrancy se Torna Realidade
O contrato EtherStore é um exemplo clássico de contrato vulnerável. Ele possui a função deposit() para guardar saldo e a função withdrawAll() para saque. O problema está na implementação de withdrawAll(): ela verifica condições, envia Ether e só depois atualiza o saldo.
O contrato Attack explorará essa vulnerabilidade. No construtor, o atacante fornece o endereço do EtherStore, podendo assim chamar suas funções. A função fallback do contrato Attack será acionada toda vez que EtherStore enviar Ether, e dentro dela continuará chamando withdrawAll() enquanto houver Ether. A função attack() inicia o processo enviando 1 Ether inicialmente ao EtherStore para passar na verificação inicial.
Como resultado, toda a reserva do EtherStore é drenada em uma única transação.
Três Estratégias para Proteger Contratos contra Reentrancy
Para proteger contratos inteligentes, existem três níveis de defesa, do mais básico ao mais completo.
Modelo noReentrant: Solução Básica de Proteção
A abordagem mais simples é usar o modificador noReentrant(). Um modificador é uma função especial em Solidity que permite alterar o comportamento de outras funções sem precisar reescrevê-las completamente.
A ideia é simples: quando uma função é protegida por noReentrant(), ela bloqueia o contrato durante toda a execução. Qualquer chamada que tente reentrar essa função falhará porque a variável de estado de bloqueio impede. Somente após a conclusão da execução e a liberação do bloqueio, outras chamadas poderão ocorrer com sucesso.
Essa solução é eficaz para proteger uma única função, mas não lida com cenários mais complexos.
Modelo Check-Effect-Interaction: Prevenção de Reentrancy Multi-Funcional
A segunda técnica, mais robusta, é aplicar o padrão Check-Effect-Interaction. Em vez de proteger apenas uma função, esse padrão altera a forma como você escreve a lógica da função.
O princípio central é: verificar condições antes (Check), atualizar o estado imediatamente após (Effect), e só então interagir com contratos externos (Interaction). Isso impede que atacantes explorem, pois ao fazerem a chamada recursiva, o saldo já foi atualizado para zero.
Ao invés de atualizar balance[msg.sender] = 0 após enviar Ether, mova essa linha para antes. Assim, mesmo que a fallback seja acionada várias vezes, a verificação sempre falhará porque o saldo já está zerado.
Esse método protege o contrato contra reentrancy de forma abrangente, mesmo quando há múltiplas funções de saque.
GlobalReentrancyGuard: Proteção Completa em Todo o Projeto
Para projetos mais complexos, com múltiplos contratos interagindo, uma solução mais abrangente é o GlobalReentrancyGuard.
Ao invés de bloquear por função, essa abordagem bloqueia em nível de todo o projeto. Você cria um contrato separado que armazena uma variável de estado de bloqueio global, e todos os demais contratos do projeto fazem referência a ele.
Imagine o seguinte cenário: um atacante chama uma função no contrato ScheduledTransfer. Após passar nas verificações, envia Ether para o AttackTransfer. A função fallback de AttackTransfer é acionada e tenta chamar novamente ScheduledTransfer. Mas, como o GlobalReentrancyGuard já bloqueou o estado global, essa chamada é impedida imediatamente.
Esse método é especialmente útil para grandes projetos com múltiplos contratos, onde reentrancy pode ocorrer entre diferentes contratos.
Escolhendo a Técnica Adequada para Seu Projeto
A escolha da estratégia depende da complexidade do seu projeto. Se seu contrato possui poucas funções de interação, noReentrant() é suficiente. Para múltiplas funções de saque, o padrão Check-Effect-Interaction é uma ótima opção. Para projetos de grande escala com muitos contratos, o GlobalReentrancyGuard oferece proteção total.
Independentemente da abordagem escolhida, o mais importante é entender como a reentrancy funciona, para que você possa identificá-la e preveni-la de forma proativa.
Para atualizações diárias sobre segurança de contratos inteligentes, revisão de código e as últimas tendências no universo Web3, acompanhe recursos especializados em segurança Solidity.