WEB3DEV

Cover image for Desenvolvimento Seguro de Contrato Inteligente 001: Padrão CEI (Checks-Effects-Interactions)
Paulo Gio
Paulo Gio

Posted on

Desenvolvimento Seguro de Contrato Inteligente 001: Padrão CEI (Checks-Effects-Interactions)

https://miro.medium.com/v2/resize:fit:1100/format:webp/1*H8mnksKqXAsNks7r-jqHqA.png

Sumário

  • Introdução
  • O que é o padrão CEI (Checks-Effects-Interactions, ou Verificações-Efeitos-Interações)
  • Por que ataques de reentrância são possíveis quando não se segue o padrão CEI?
  • Exemplo de Ataque de Reentrância não seguindo o padrão CEI
  • Como aplicar o padrão CEI
  • Conclusões
  • Referências

Introdução

Neste artigo, discutiremos o padrão CEI, ou padrão de Verificações-Efeitos-Interações, um conceito crucial no desenvolvimento de contratos inteligentes. Ao seguir este padrão, os desenvolvedores podem melhorar significativamente a segurança de seus contratos inteligentes, pois a ausência deste padrão pode introduzir o famoso vetor de ataque de reentrância.

Se você quiser se conectar comigo, siga-me no twitter em @s3rgiomazari3go, minhas DMs estão disponíveis para ajudar.

O que é o padrão CEI?

O padrão CEI é um conceito crucial no desenvolvimento de contratos inteligentes que visa melhorar a segurança, garantindo que chamadas externas sejam feitas apenas após todas as alterações de estado terem ocorrido. Esta é uma prática recomendada que todos os desenvolvedores devem ter em mente ao criar contratos inteligentes seguros na blockchain, especialmente usando a linguagem de programação Solidity para blockchains compatíveis com a EVM.

O padrão CEI requer que qualquer modificação de estado em uma função ocorra antes que uma chamada externa seja feita. Em essência, isso significa que antes de fazer uma chamada externa, a função deve realizar todas as mudanças de estado necessárias, como atualizar os dados do contrato (por exemplo, o saldo de um usuário), verificar a validade dos valores de entrada, e assim por diante.

Uma violação do padrão CEI pode levar a consequências desastrosas. Se você quiser saber mais sobre as consequências de não seguir esta melhor prática, veja o exemplo abaixo.

Por que ataques de reentrância são possíveis quando não se segue o padrão CEI?

Quando uma chamada externa é feita, o controle é transferido para outro contrato ou uma terceira parte, que pode aproveitar o estado inalterado para executar código malicioso que pode comprometer a segurança do contrato. Isso pode resultar em um cenário de reentrância, onde um ator mal-intencionado pode reentrar repetidamente na função do contrato e alterar seu fluxo esperado.

https://miro.medium.com/v2/resize:fit:1100/format:webp/0*JJAgKJR2tNtkBb2g.png

Imagem da geeksforgeeks.

Outra definição de Reentrância por BlockSec:

Em um contrato inteligente, a reentrância pode ocorrer quando uma função executa uma chamada externa de outro contrato, que por sua vez invoca a função original (ou outras funções) antes que a invocação original retorne. Se a chamada externa for controlada por uma entidade não confiável (por exemplo, um contrato malicioso), isso pode levar a um resultado inesperado. Isso porque, em algumas funções, o resultado depende do estado do contrato. O estado do contrato será atualizado após a chamada externa. No entanto, a invocação reentrante da função usará o estado antigo em vez do atualizado.

Exemplo de Ataque de Reentrância não seguindo o padrão CEI

Código do desafio Ethernaut não usando o padrão CEI, introduzindo um vetor de ataque de reentrância:

Código Vulnerável

https://miro.medium.com/v2/resize:fit:1100/format:webp/1*XVSN5VRsGT45vrTAIW39kQ.png

O ataque de reentrância consistirá nas seguintes etapas:

  1. A vítima deposita 0.001 ETH no contrato vulnerável;
  2. O invasor chama a função de ataque (attack) no contrato AttackerContract. Esta função primeiro deposita 0.01 ETH no cofre usando a função donate. Isso é feito para ter um saldo no cofre que pode ser retirado do AttackerContract.
  3. O atacante então chama a função de saque (withdraw) do cofre, tentando sacar este 0.01 ETH. Como o atacante tem um saldo no cofre, a retirada é bem sucedida.
  4. O cofre transfere o 0.01 ETH do saldo do atacante para o AttackerContract.
  5. O AttackerContract recebe 0.01 ETH em sua função receive, que é acionada pela transferência. Neste ponto, o saldo do atacante no cofre ainda não foi alterado.
  6. Dentro da função receive, o atacante chama a função withdraw do cofre novamente, tentando sacar 0.01 ETH. Como o saldo do atacante no cofre ainda não foi atualizado, a retirada é bem sucedida novamente.
  7. O cofre transfere um adicional de 0.001 (saldo restante) ETH para o AttackerContract, que agora executou com sucesso um ataque de reentrância, chamando repetidamente a função de saque e drenando o contrato.

AttackerContract

https://miro.medium.com/v2/resize:fit:1100/format:webp/1*uQaKC2Tz4iNBqeYaSYH_zw.png

Veja o código do AttackerContract aqui:

Teste explorando o código vulnerável acima

1.Saldo inicial do contrato vulnerável = 0.001 ETH.

https://miro.medium.com/v2/resize:fit:786/format:webp/1*uYBErdfZflb-AzUTWF9teg.png

2.Implantando o AttackerContract, passando como argumento o endereço do contrato vulnerável.

https://miro.medium.com/v2/resize:fit:1100/format:webp/1*f6Iv2glYy5JAJr1uscHwTw.png

Endereço do contrato vulnerável

https://miro.medium.com/v2/resize:fit:1100/format:webp/1*AYHqRY37uQPmC5s77_oLTA.png

Implantando o AttackerContract

1.Saldo do AttackerContract antes do ataque.

https://miro.medium.com/v2/resize:fit:828/format:webp/1*njHo4ytU5JYoyIql1QxnYg.png

2.Atacante inicia a função attack do AttackerContract (Depósito de 0.01ETH do atacante EOA + Saque do mesmo 0.01 ETH).

https://miro.medium.com/v2/resize:fit:592/format:webp/1*jb6zyFp9hT19IQc6GwzcKQ.png

3.O atacante obtém o saldo do AttackerContract usando a função getBalance, e agora ele tem o 0.01 ETH que enviou mais o 0.001 ETH que estava no contrato antes do ataque.

https://miro.medium.com/v2/resize:fit:828/format:webp/1*-AMUN2SPHHiU9yIUx2JH-A.png

Saldo do AttackerContract após o ataque

4.O contrato vulnerável agora teve seus fundos drenados.

https://miro.medium.com/v2/resize:fit:786/format:webp/1*BUJlOCbn0L7pCywye5BwhQ.png

Saldo do contrato vulnerável após o ataque

Como aplicar o padrão CEI

Para implementar o padrão CEI, os desenvolvedores devem seguir três etapas:

  1. Verificações: A função deve validar todos os parâmetros de entrada para garantir que sejam válidos.
  2. Efeitos: Todas as alterações de estado devem ocorrer, incluindo a atualização dos dados do contrato.
  3. Interação: Finalmente, todas as chamadas externas devem ser feitas.

Conclusões:

O padrão CEI, ou padrão de Verificações-Efeitos-Interações, é uma prática de segurança crítica para o desenvolvimento de contratos inteligentes. Ao seguir o padrão CEI, os desenvolvedores podem melhorar significativamente a segurança de seus contratos inteligentes, garantindo que as chamadas externas sejam feitas apenas após todas as alterações de estado terem ocorrido. Isso pode ajudar a prevenir ataques de reentrância, que são uma das vulnerabilidades de segurança mais comuns em contratos inteligentes.

O padrão CEI é relativamente simples de implementar, e existem vários recursos disponíveis para ajudar os desenvolvedores a aprender mais sobre ele. Eu encorajo todos os desenvolvedores que estão construindo contratos inteligentes a adotar o padrão CEI como parte de suas melhores práticas de segurança.

Obrigado por ler!

Referências:

Checks Effects Interactions by Fravoll

Smart Contract : Security Patterns

Reentrancy Attack in Smart Contracts — GeeksForGeeks

Artigo original publicado por Sergio Mazariego. Traduzido por Paulinho Giovannini.

Top comments (0)