Diretrizes de segurança do contrato inteligente
Siga estas recomendações de alto nível para construir contratos inteligentes mais seguros.
Padrões de design
O design do contrato deve ser discutido antecipadamente, antes de escrever qualquer linha de código.
Documentação e especificações
A documentação pode ser escrita em diferentes níveis, e deve ser atualizada durante a implementação dos contratos:
- Uma descrição simples em inglês do sistema, descrevendo o que os contratos fazem e qualquer suposição no código.
- Esquemas e diagramas arquitetônicos, incluindo as interações de contratos e a máquina de estado do sistema. Impressoras do Slither(opens in a new tab) podem ajudar a gerar esses esquemas.
- Documentação de código Thorough, o formato Natspec(opens in a new tab) pode ser usado para Solidity.
Computação on-chain vs off-chain
- Mantenha o máximo de código que puder off-chain (fora da cadeia). Mantenha a menor camada on-chain (dentro da cadeia). Pré-processe dados com código off-chain de tal forma que a verificação on-chain torne-se simples. Você precisa de uma lista ordenada? Ordene a lista off-chain, então apenas verifique a ordem on-chain.
Capacidade de Atualização
Nós discutimos as diferentes soluções de atualização em nosso blog(opens in a new tab). Faça ou não uma escolha deliberada para apoiar a capacidade de atualização antes de escrever qualquer código. A decisão irá influenciar como você estrutura nosso código. Em geral, recomendamos:
- Favorecer a migração do contrato(opens in a new tab) sobre a atualização. O sistema de migração tem muitas das mesmas vantagens do que ser atualizável, sem suas desvantagens.
- Usando o padrão de separação de dados sobre o proxy delegatecallproxy. Se o seu projeto tem uma separação de abstração clara, a atualizabilidade usando a separação de dados exigirá apenas alguns ajustes. O delegatecallproxy exige conhecimento de EVM e é altamente susceptível de erros.
- Documentar o procedimento de migração/atualização antes da implantação. Se você tiver que reagir sob o estresse sem quaisquer diretrizes, você cometerá erros. Escreva o procedimento a seguir com antecedência. Ele deve incluir:
- As exigências que iniciam os novos contratos
- Onde são armazenadas as chaves e como acessá-las
- Como verificar a implantação de arquivos! Desenvolva e teste um script de pós-implantação.
Orientações de implementação
Esforço pela simplicidade. Sempre use a solução mais simples que se encaixa em seu propósito. Qualquer membro da sua equipe deve ser capaz de entender a sua solução.
Composição de funções
A arquitetura da sua base de código deve facilitar a revisão do seu código. Evite escolhas arquitetônicas que diminuam a capacidade de raciocínio sobre sua exatidão.
- Divida a lógica do seu sistema, seja por meio de vários contratos ou agrupando funções semelhantes juntas (por exemplo, autenticação, aritmética, ...).
- Escreva funções pequenas, com um propósito claro. Isso facilitará uma revisão mais tranquila e permitirá o teste de componentes individuais.
Herança
- Mantenha a herança gerenciável. A herança deve ser usada para dividir a lógica, no entanto, seu projeto deve visar minimizar a profundidade e a largura da árvore de herança.
- Use a impressora de herança de Slither(opens in a new tab) para verificar a hierarquia dos contratos. A impressora de herança irá ajudá-lo a rever o tamanho da hierarquia.
Eventos
- Registre todas as operações cruciais. Os eventos ajudarão a depurar o contrato durante o desenvolvimento e a monitorá-lo após a implantação.
Evite armadilhas conhecidas
- Esteja ciente dos problemas de segurança mais comuns. Há muitos recursos on-line para aprender sobre problemas comuns, como Ethernaut CTF(opens in a new tab), Capture o Ether(opens in a new tab), ou contratos não tão inteligentes(opens in a new tab).
- Esteja ciente das seções de avisos na documentação Solidity(opens in a new tab) As seções de avisos irão informá-lo sobre comportamentos não óbvios da linguagem.
Dependências
- Use bibliotecas testadas. A importação de código de bibliotecas testadas reduzirá a probabilidade de você escrever código com erros. Se você deseja escrever um contrato ERC20, use OpenZeppelin(opens in a new tab).
- Use um gerenciador de dependências; evite "copiar-e-colar" códigos. Se você estiver contando com uma fonte externa, então você deve mantê-lo atualizado com a fonte original.
Teste e Validação
- Escreva testes unitários completos. Um conjunto extenso de testes é crucial para construir softwares de alta qualidade.
- Escreva propriedades e verificações personalizadas com Slither(opens in a new tab), Echidna(opens in a new tab) e Manticore(opens in a new tab). Ferramentas automatizadas ajudarão a garantir que o seu contrato é seguro. Revise o resto deste guia para aprender a escrever propriedades e verificações eficientes.
- Use o crytic.io(opens in a new tab). O Critic integra-se ao Github, fornece acesso a detectores privados do Slither e executa verificações de propriedade personalizadas pelo Echidna.
Solidity
- Favoreça a Solidity 0.5 em vez de 0.4 e 0.6. Em nossa opinião, a Solidity 0.5 é mais seguro e tem melhores práticas incorporadas que a 0.4. A Solidity 0.6 provou ser demasiado instável para produção e precisa de tempo para amadurecer.
- Use um lançamento estável para compilar; use a versão mais recente para verificar se há avisos. Verifique se o seu código não relatou problemas com a versão mais recente do compilador. No entanto, a Solidity tem um ciclo de lançamento rápido e tem um histórico de erros do compilador, então não recomendamos a versão mais recente para implantar (veja a recomendação de versão solc do Slither(opens in a new tab)).
- Não use montagem embutida. A montagem requer experiência em EVM. Não escreva o código EVM se você não tiver dominado o Yellow Paper da Ethereum.
Orientações de implantação
Uma vez que o contrato tenha sido desenvolvido e implantado:
- Monitore seus contratos. Observe os acessos e esteja pronto para reagir em caso de comprometimento do contrato ou da carteira.
- Adicione suas informações de contato em contatos de segurança da blockchain(opens in a new tab). Essa lista ajuda a terceiros a entrar em contato com você caso uma falha de segurança seja descoberta.
- Proteja as carteiras de usuários privilegiados. Siga nossas melhores práticas(opens in a new tab) se você armazenar chaves em carteiras físicas (hardware).
- Tenha uma resposta ao plano de incidentes. Considere que seus contratos inteligentes possam ser comprometidos. Mesmo que seus contratos estejam livres de erros, um invasor pode assumir o controle das chaves do proprietário do contrato.
Última edição: @pettinarip(opens in a new tab), 8 de dezembro de 2023