Visão geral da infraestrutura Blockchain — Estados
Blockchains de execução de código descentralizado forneceram a infraestrutura de nível básico para uma variedade de aplicativos descentralizados, criando uma nova geração de aplicativos Web 3.0. Os aplicativos da Web 3.0 operam na cadeia (on-chain) por meio de contratos inteligentes - transações de blockchain contendo código executável que pode ser usado para criar programas automatizados. Apesar de sua utilidade, os contratos inteligentes contêm uma variedade de vulnerabilidades devida às configurações das máquinas virtuais blockchain e suas limitações na execução do código.
Blockchains são limitadas em escalabilidade na taxa de transferência, tanto em termos de capacidade transacional quanto computacional. Dado que os contratos inteligentes são transações contendo linhas de códigos executáveis, as transações de contratos inteligentes devem ser processadas em blocos, assim como as transações normais. Os blocos são adicionados continuamente em um período de tempo semi-regular determinado por algoritmos. Dado o armazenamento limitado de dados em uma blockchain, cada processo individual não é registrado explicitamente em cada bloco. Em vez disso, um hash criptográfico de processos é registrado como o estado da blockchain. Da mesma forma, dentro do contrato inteligente, os dados são armazenados apenas se forem designados como uma variável de estado - o que significa que são armazenados na cadeia em vez de armazenados dinamicamente.
Dada a escalabilidade limitada dos contratos inteligentes e o alto custo de implantação, os contratos inteligentes geralmente contêm várias funções para oferecer suporte a operações de aplicativos descentralizados. Cada função individual pode ter vários processos antes de uma mudança de estado. Em um artigo anterior, as vulnerabilidades de reentrância foram discutidas para processos de funções individuais antes das mudanças de estado. No entanto, a reentrância não é a única vulnerabilidade associada a chamadas de função e mudanças de estado. Outra vulnerabilidade notável associada a chamadas de função e mudanças de estado é a dependência de estado de função cruzada.
Vulnerabilidades de dependência de estado entre funções
Dependências de estado de função cruzada são vulnerabilidades nas quais duas ou mais funções dependem do mesmo estado de contrato. As vulnerabilidades de dependência de estado de função cruzada são um exemplo de bugs de condição de corrida — bugs que surgem quando o comportamento de um sistema depende de uma sequência de tempo ou operações para produzir os resultados esperados. Os ataques de reentrância podem ser considerados erros de condição de corrida, uma vez que o ataque ocorre a partir de uma reentrada inesperada no contrato de destino, interrompendo o fluxo de controle. Os ataques de reentrância são semelhantes aos ataques de dependência de estado de função cruzada em que os fluxos de controle esperados são interrompidos por chamadas de contrato. No entanto, ao contrário dos ataques de reentrância, o ataque não é necessariamente baseado em uma função de fallback de contrato externo, mas sim em duas funções em um contrato direcionado que dependem do mesmo estado.
Quando duas funções dependem do mesmo estado de contrato, pode existir uma vulnerabilidade na medida em que é possível chamar duas funções simultaneamente. Quando duas funções são chamadas simultaneamente externamente, ambos os processos podem ser executados antes das transições de estado esperadas, produzindo resultados indesejados. Sempre que um estado é sequencialmente dependente e várias funções dependem desse estado, chamadas externas simultâneas de funções podem ser coordenadas em um ataque para explorar a mudança de estado não atualizada. Se o estado não for atualizado para cada chamada, existe uma vulnerabilidade. Para maior clareza, um exemplo de dependência entre estados pode ser observado abaixo.
Dentro desse código, há duas funções que compartilham o mesmo estado — transfer e drawlBalance. Ambas as funções permitem que um usuário remova fundos do contrato inteligente e os envie para um endereço externo. Ambas as funções também dependem do estado de userBalances ou do saldo do usuário. Embora ambas as funções atualizem o estado do saldo de acordo com o valor sacado, tais atualizações ocorrem no final da função, ou seja, é o último processo. Assim, um invasor pode chamar simultaneamente ambas as funções, permitindo uma retirada adicional antes de uma atualização de saldo. Embora o valor retirado não exceda o saldo, um invasor pode retirar qualquer valor até o dobro de seu saldo, efetivamente “gastando em dobro” seu saldo.
Mitigação de vulnerabilidades de dependência de estado entre funções
A dependência de estado de função cruzada é uma vulnerabilidade complexa sem uma correção fácil. Dado o alto custo de armazenamento de dados em contratos inteligentes, a realidade inconveniente é que a maioria dos contratos inteligentes tem armazenamento de estado limitado e deve contar com um estado para várias funções. Por exemplo, o saldo de um contrato inteligente pode ser usado para diversas funções: saques, transferências, compras etc. Como tal, é difícil implementar um estado diferente para cada função. Da mesma forma, a dependência entre estados pode até se estender a vários contratos inteligentes interconectados. Embora soluções simples possam não existir, existem soluções.
Existem várias soluções para dependências de estado de cadeia cruzada. A primeira é identificar funções com possíveis chamadas externas e garantir que todos os processos internos ocorram antes de possíveis chamadas de funções externas - principalmente mudanças de estado. Outra solução é implementar a exclusão mútua, permitindo que um contrato inteligente bloqueie efetivamente um estado, com controle de acesso adequado. No entanto, a exclusão mútua torna-se muito mais difícil de implementar quando vários contratos estão envolvidos. Em última análise, existe uma variedade de soluções, mas elas requerem precisão para implementar. Em qualquer caso, é imperativo que qualquer proprietário de contrato inteligente audite seus contratos inteligentes e tenha cuidado com quaisquer vulnerabilidades, incluindo dependências de estado de função cruzada.
Artigo escrito por Benjamin Chai e traduzido por Marcelo Panegali
Top comments (0)