Introdução
É fácil gerar números aleatórios em linguagens de programação como JavaScript ou Python, mas é mais desafiador fazer isso de forma segura em Solidity. Solidity requer aleatoriedade segura para diferentes aplicações, como jogos e loterias. A razão é que as blockchains são determinísticas, o que significa que a saída de qualquer função é sempre a mesma para a mesma entrada. Isso torna difícil gerar números verdadeiramente aleatórios na blockchain, já que qualquer algoritmo usado para gerar aleatoriedade pode ser explorado.
Este artigo abordará o papel da aleatoriedade em Solidity, fontes de aleatoriedade ruim, como obter aleatoriedade usando as funções VRF do Oráculo Chainlink, hacks e técnicas de mitigação.
O Papel da Aleatoriedade em Solidity
A aleatoriedade é um elemento importante de muitas aplicações Web3, incluindo jogos na cadeia, loterias e protocolos de finanças descentralizadas (DeFi). É usada para criar resultados imprevisíveis, que podem ser adicionados a mecânicas de jogabilidade, garantir distribuição justa de recompensas e prevenir fraudes.
Por exemplo, em um jogo Web3, a aleatoriedade pode ser usada para determinar o resultado de uma batalha, a raridade de um item NFT ou a distribuição de espólios. Em uma loteria, a aleatoriedade é usada para selecionar os números vencedores. Em protocolos DeFi, a aleatoriedade pode ser usada para gerar chaves privadas, que são usadas para garantir os fundos dos usuários.
Quando se trata de aleatoriedade, existem duas formas diferentes, a saber, pseudo randomicidade e verdadeira aleatoriedade. A pseudo randomicidade é gerada por algoritmos determinísticos, enquanto a verdadeira aleatoriedade depende de fontes de entropia imprevisíveis e imparciais.
Números pseudo-randômicos parecem ser aleatórios, mas são gerados por uma fórmula. Isso significa que podem ser previstos se você conhecer a fórmula e o valor inicial da semente.
A verdadeira aleatoriedade é gerada por processos físicos que são inerentemente imprevisíveis. A verdadeira aleatoriedade é usada para aplicações mais sensíveis à segurança, como a geração de chaves criptográficas.
Aleatoriedade Ruim
A vulnerabilidade de aleatoriedade ruim ocorre quando um contrato inteligente depende de uma fonte de aleatoriedade que não é verdadeiramente aleatória ou que pode ser prevista por um invasor. Isso pode permitir que um atacante manipule o resultado de uma transação ou obtenha uma vantagem injusta sobre outros usuários.
Existem diferentes fontes de aleatoriedade ruim em contratos inteligentes, e vamos analisar algumas delas:
- Usar o hash do bloco como fonte de aleatoriedade:
O hash do bloco é um valor derivado do conteúdo de um bloco na blockchain Ethereum. Ele é considerado pseudo-randômico porque é baseado nas transações e outros dados contidos no bloco, mas não é verdadeiramente aleatório porque é determinado pelo conteúdo do bloco, que pode ser conhecido ou previsível por um invasor.
- Usar o carimbo de data/hora (timestamp) atual do bloco como fonte de aleatoriedade:
Não é recomendado usar block.timestamp
como fonte de aleatoriedade, pois pode ser influenciado ou manipulado por validadores (mineradores). Os validadores têm um certo controle sobre o valor de block.timestamp
. Eles podem ajustar o carimbo de data/hora de um bloco que estão minerando, desde que esteja dentro de uma faixa de tolerância específica. Isso significa que os mineradores podem potencialmente manipular o carimbo de data/hora para gerar resultados específicos em contratos inteligentes que dependem do block.timestamp
para aleatoriedade. Em um nível mais elevado, pode ocorrer um ataque de front-running.
- Usar variáveis locais e de armazenamento como fonte de aleatoriedade:
Variáveis locais e variáveis de armazenamento em Solidity podem ser usadas para gerar valores aleatórios ou tomar decisões que deveriam ser imprevisíveis. No entanto, os valores dessas variáveis são visíveis a todos os participantes do contrato, tornando possível para atores maliciosos prever ou manipular os resultados.
Invasão causada por aleatoriedade ruim
Vamos analisar uma invasão do mundo real que ocorreu devido a uma aleatoriedade ruim em um contrato:
Invasão do Fomo3D
O Fomo3D é um jogo de loteria onde a última pessoa a comprar uma chave ganha. Os jogadores podem comprar chaves durante uma rodada, e o preço das chaves aumenta ligeiramente a cada compra. Os jogadores também ganham renda passiva do jogo à medida que as chaves são compradas. Quando a rodada termina, a última pessoa a comprar uma chave ganha o pote.
O que atraiu os jogadores para o jogo foram os airdrops. Airdrops são prêmios dados a jogadores aleatórios. Isso também atraiu invasores.
Os vencedores são escolhidos completamente aleatoriamente. O contrato Fomo3D usa várias fontes de aleatoriedade para gerar números aleatórios, como o tempo de criação do bloco, o endereço do minerador do bloco atual e o endereço do jogador atual, que explicamos anteriormente que são fontes de aleatoriedade ruim.
Aqui está a fórmula usada:
contract FoMo3Dlong is modularLong {
/**
* @dev gera um número aleatório entre 0-99 e verifica se isso
* resultou em uma vitória no airdrop
* @return temos um vencedor?
*/
function airdrop()
private
view
returns(bool)
{
uint256 seed = uint256(keccak256(abi.encodePacked(
(block.timestamp).add
(block.difficulty).add
((uint256(keccak256(abi.encodePacked(block.coinbase)))) / (now)).add
(block.gaslimit).add
((uint256(keccak256(abi.encodePacked(msg.sender)))) / (now)).add
(block.number)
)));
if((seed - ((seed / 1000) * 1000)) < airDropTracker_)
return(true);
else
return(false);
}
}
Usar este método para determinar vencedores aleatórios para o airdrop torna o contrato Fomo3D previsível e vulnerável a ataques.
O invasor realizou seu ataque usando um contrato para enganar o contrato Fomo3D, fazendo-o acreditar que era um EOA (porque apenas EOAs são elegíveis para airdrops e não contratos) e também foi capaz de manipular a aleatoriedade do contrato inteligente Fomo3D e obter o airdrop, fugindo com muitos ethers.
Obtendo Aleatoriedade Usando o Chainlink VRF
A Chainlink é uma rede de oráculos descentralizada que fornece feeds de dados seguros e confiáveis e computação fora da cadeia para contratos inteligentes. Ela permite que contratos inteligentes acessem dados e eventos do mundo real e realizem complexas computações fora da cadeia sem comprometer sua segurança.
A Chainlink é utilizada por uma ampla gama de aplicações descentralizadas, incluindo protocolos DeFi, plataformas de seguros e aplicativos de jogos. Um dos principais serviços da Chainlink é o VRF (função aleatória verificável), no qual você obtém números aleatórios.
O Chainlink VRF é um gerador de números aleatórios (RNG) comprovadamente justo e verificável que permite que contratos inteligentes usem números aleatórios sem sacrificar a segurança ou a usabilidade. Para cada solicitação, o Chainlink VRF gera um ou mais números aleatórios e uma prova criptográfica de como foram gerados. A prova é publicada e verificada na blockchain antes que qualquer aplicativo possa usá-la. Esse processo garante que ninguém, incluindo operadores de oráculos, mineradores, usuários ou desenvolvedores de contratos inteligentes, possa interferir ou manipular os resultados.
Os métodos de assinatura e financiamento direto são as duas formas de gerar números aleatórios usando o Chainlink VRF.
O método de assinatura é bom para solicitações regulares de aleatoriedade, onde você precisa solicitar aleatoriedade com frequência. Com esse método, você cria uma conta de assinatura e a financia antecipadamente com tokens LINK. Então, quando precisar de aleatoriedade, basta solicitar da sua conta de assinatura. Os custos do VRF são calculados após o atendimento de suas solicitações e, em seguida, deduzidos do saldo de sua assinatura.
O método de financiamento direto é bom para solicitações esporádicas e únicas de aleatoriedade. Com esse método, você não precisa criar uma conta de assinatura. Em vez disso, você financia diretamente o contrato consumidor com tokens LINK antes de solicitar a aleatoriedade. Os custos do VRF são estimados e cobrados no momento da solicitação.
A principal diferença entre os dois métodos é que o método de assinatura é mais eficiente para solicitações regulares, enquanto o método de financiamento direto é mais eficiente para solicitações esporádicas.
A Chainlink forneceu um guia simples sobre como usar o Chainlink V2 VRF para gerar números aleatórios em seus contratos inteligentes em sua documentação.
Técnicas de Mitigação:
Para evitar o uso de aleatoriedade inadequada no Solidity, é importante implementar aleatoriedade segura em seus contratos inteligentes ao construir suas aplicações blockchain.
- Use o Chainlink VRF: Chainlink VRF é uma maneira segura de gerar números aleatórios em seus projetos de contrato inteligente. Sempre que desejar implementar aleatoriedade em seu contrato Solidity, evite usar dados relacionados ao bloco, como hashes de bloco, carimbos de data ou números de bloco, para gerar números aleatórios, pois podem ser manipulados. É aconselhável integrar o Chainlink VRF.
- Mantenha seu contrato inteligente atualizado com as últimas correções de segurança e melhores práticas e faça auditorias regulares para identificar quaisquer vulnerabilidades, especialmente aquelas relacionadas à aleatoriedade.
Conclusão:
A aleatoriedade ruim é uma falha séria de segurança em contratos Solidity. Pode ser explorada por invasores para manipular o resultado de contratos inteligentes, resultando em perdas financeiras para os usuários. Os desenvolvedores devem estar cientes dessa vulnerabilidade e tomar medidas para mitigá-la, como o uso de oráculos descentralizados que fornecem funções seguras de aleatoriedade, como o Chainlink VRF.
Artigo escrito por Natachi Nnamaka. Traduzido por Marcelo Panegali.
Oldest comments (0)