Acabei de querer partilhar um problema de segurança de smart contracts que muitos programadores ainda ignoram — o ataque de reentrancy. Se estiver a construir smart contracts em Solidity, isto é algo que tem de compreender bem.



De forma simples, a reentrancy acontece quando um contrato chama outro contrato, e esse contrato pode chamar novamente o contrato original enquanto ainda está a ser executado. Imagine que tem o ContractA que contém 10 Ether e o ContractB envia 1 Ether para ele. Quando o ContractB levanta dinheiro, o ContractA verifica se o saldo é maior do que 0; se for, envia Ether de volta. No entanto, se o ContractB tiver uma fallback function (função de fallback), ele pode chamar novamente a função de levantamento do ContractA enquanto esta ainda não terminou. Resultado? O saldo do ContractB continua a ser registado como 1 Ether, por isso ele recebe mais 1 Ether, e assim por diante, repetidamente, até o ContractA ficar sem fundos.

Como funciona este ataque? O atacante precisa de duas coisas: uma função attack() para começar, e uma fallback function para chamar novamente a função de levantamento. A fallback function é uma função externa especial, sem nome, sem parâmetros; qualquer pessoa a pode ativar ao chamar uma função inexistente, sem enviar dados, ou ao enviar Ether sem quaisquer dados adicionais.

Há um exemplo concreto: o contrato EtherStore tem uma função deposit() que armazena o saldo e uma função withdrawAll() que levanta tudo. O problema é que withdrawAll() verifica o saldo, envia Ether e só depois atualiza o saldo para 0. Isto cria uma brecha para que a ataque de reentrancy ocorra.

Então como se protege? Vou mostrar três formas.

Em primeiro lugar, usar o modifer noReentrant. A ideia é muito simples: bloquear o contrato enquanto a função está a ser executada. Se alguém tentar chamar novamente essa função, tem de passar na verificação do lock primeiro; mas o lock só será desbloqueado depois de a função terminar. O modifer é um tipo de função especial que permite adicionar condições a outras funções sem precisar de reescrever toda a lógica.

Em segundo lugar, aplicar o padrão Check-Effect-Interaction. Em vez de verificar a condição, enviar fundos e só depois atualizar o saldo, deve verificar primeiro, atualizar o saldo imediatamente (antes de enviar fundos), e só depois realizar a interação com a parte externa. Desta forma, mesmo que ocorra reentrancy, o saldo já terá sido atualizado para 0, por isso o atacante não conseguirá levantar mais.

Em terceiro lugar, se o seu projeto tiver muitos contratos a interagir entre si, precisa de GlobalReentrancyGuard. Em vez de bloquear apenas uma função, bloqueia todo o sistema com uma variável de estado guardada num contrato separado. Quando qualquer função de qualquer contrato é chamada, ela verifica se o sistema está bloqueado. Se estiver, a transação é rejeitada. Isto é especialmente útil quando tem contratos como ScheduledTransfer a enviar fundos para AttackTransfer — o GlobalReentrancyGuard impede que toda a cadeia do ataque de reentrancy aconteça.

O bom destas três abordagens é que pode combiná-las conforme a situação. Uma função importante? Use noReentrant. Muitas funções relacionadas? Use o Check-Effect-Interaction. Todo o projeto é complexo? Use o GlobalReentrancyGuard. Compreender a reentrancy e como preveni-la vai ajudar a construir smart contracts muito mais seguros.
Ver original
Esta página pode conter conteúdo de terceiros, que é fornecido apenas para fins informativos (não para representações/garantias) e não deve ser considerada como um endosso de suas opiniões pela Gate nem como aconselhamento financeiro ou profissional. Consulte a Isenção de responsabilidade para obter detalhes.
  • Recompensa
  • Comentário
  • Repostar
  • Compartilhar
Comentário
Adicionar um comentário
Adicionar um comentário
Sem comentários
  • Em alta na Gate Fun

    Ver projetos
  • Cap. de M.:$2.24KHolders:1
    0.00%
  • Cap. de M.:$2.24KHolders:0
    0.00%
  • Cap. de M.:$2.23KHolders:1
    0.00%
  • Cap. de M.:$2.24KHolders:1
    0.00%
  • Cap. de M.:$0.1Holders:0
    0.00%
  • Marcar