Vai al contenuto principale

Linee guida per la sicurezza degli smart contract

Solidity
smart contract
sicurezza
Intermedio
Trailofbits
6 settembre 2020
5 minuti di lettura

Segui queste raccomandazioni di alto livello per creare smart contract più sicuri.

Linee guida per la progettazione

La progettazione del contratto dovrebbe essere discussa in anticipo, prima di scrivere qualsiasi riga di codice.

Documentazione e specifiche

La documentazione può essere scritta a diversi livelli e dovrebbe essere aggiornata durante l'implementazione dei contratti:

  • Una descrizione del sistema in linguaggio semplice, che descriva cosa fanno i contratti e qualsiasi presupposto sulla base di codice.
  • Schemi e diagrammi architetturali, incluse le interazioni del contratto e la macchina a stati del sistema. I printer di Slither (opens in a new tab) possono aiutare a generare questi schemi.
  • Documentazione approfondita del codice, il formato NatSpec (opens in a new tab) può essere utilizzato per Solidity.

Calcolo onchain vs offchain

  • Mantieni quanto più codice possibile offchain. Mantieni ridotto il livello onchain. Pre-elabora i dati con codice offchain in modo tale che la verifica onchain sia semplice. Hai bisogno di un elenco ordinato? Ordina l'elenco offchain, quindi controllane solo l'ordine onchain.

Aggiornabilità

Abbiamo discusso le diverse soluzioni di aggiornabilità nel nostro post sul blog (opens in a new tab). Fai una scelta consapevole se supportare o meno l'aggiornabilità prima di scrivere qualsiasi codice. La decisione influenzerà il modo in cui strutturi il tuo codice. In generale, raccomandiamo di:

  • Preferire la migrazione del contratto (opens in a new tab) rispetto all'aggiornabilità. I sistemi di migrazione hanno molti degli stessi vantaggi di quelli aggiornabili, senza i loro svantaggi.
  • Utilizzare il pattern di separazione dei dati rispetto a quello del proxy delegatecall. Se il tuo progetto ha una chiara separazione delle astrazioni, l'aggiornabilità tramite la separazione dei dati richiederà solo pochi aggiustamenti. Il proxy delegatecall richiede esperienza con l'EVM ed è altamente soggetto a errori.
  • Documentare la procedura di migrazione/aggiornamento prima della distribuzione. Se devi reagire sotto stress senza alcuna linea guida, commetterai degli errori. Scrivi in anticipo la procedura da seguire. Dovrebbe includere:
    • Le chiamate che avviano i nuovi contratti
    • Dove sono archiviate le chiavi e come accedervi
    • Come verificare la distribuzione! Sviluppa e testa uno script post-distribuzione.

Linee guida per l'implementazione

Punta alla semplicità. Usa sempre la soluzione più semplice adatta al tuo scopo. Qualsiasi membro del tuo team dovrebbe essere in grado di comprendere la tua soluzione.

Composizione delle funzioni

L'architettura della tua base di codice dovrebbe rendere il tuo codice facile da revisionare. Evita scelte architetturali che riducono la capacità di ragionare sulla sua correttezza.

  • Suddividi la logica del tuo sistema, tramite più contratti o raggruppando funzioni simili (ad esempio, autenticazione, aritmetica, ...).
  • Scrivi funzioni piccole, con uno scopo chiaro. Questo faciliterà la revisione e consentirà il test dei singoli componenti.

Ereditarietà

  • Mantieni l'ereditarietà gestibile. L'ereditarietà dovrebbe essere utilizzata per dividere la logica, tuttavia, il tuo progetto dovrebbe mirare a ridurre al minimo la profondità e l'ampiezza dell'albero di ereditarietà.
  • Usa il printer dell'ereditarietà (opens in a new tab) di Slither per controllare la gerarchia dei contratti. Il printer dell'ereditarietà ti aiuterà a revisionare le dimensioni della gerarchia.

Eventi

  • Registra nei log tutte le operazioni cruciali. Gli eventi aiuteranno a eseguire il debug del contratto durante lo sviluppo e a monitorarlo dopo la distribuzione.

Evita le insidie note

Dipendenze

  • Usa librerie ben testate. Importare codice da librerie ben testate ridurrà la probabilità di scrivere codice con bug. Se vuoi scrivere un contratto ERC-20, usa OpenZeppelin (opens in a new tab).
  • Usa un gestore di dipendenze; evita di copiare e incollare il codice. Se ti affidi a una fonte esterna, devi mantenerla aggiornata con la fonte originale.

Test e verifica

  • Scrivi unit test approfonditi. Una suite di test estesa è cruciale per creare software di alta qualità.
  • Scrivi controlli e proprietà personalizzati per Slither (opens in a new tab), Echidna (opens in a new tab) e Manticore (opens in a new tab). Gli strumenti automatizzati aiuteranno a garantire che il tuo contratto sia sicuro. Rivedi il resto di questa guida per imparare a scrivere controlli e proprietà efficienti.
  • Usa crytic.io (opens in a new tab). Crytic si integra con GitHub, fornisce accesso ai rilevatori privati di Slither ed esegue controlli di proprietà personalizzati da Echidna.

Solidity

  • Preferisci Solidity 0.5 rispetto a 0.4 e 0.6. A nostro avviso, Solidity 0.5 è più sicuro e ha migliori pratiche integrate rispetto a 0.4. Solidity 0.6 si è dimostrato troppo instabile per la produzione e ha bisogno di tempo per maturare.
  • Usa una versione stabile per compilare; usa l'ultima versione per controllare gli avvisi. Verifica che il tuo codice non abbia problemi segnalati con l'ultima versione del compilatore. Tuttavia, Solidity ha un ciclo di rilascio rapido e una storia di bug del compilatore, quindi non raccomandiamo l'ultima versione per la distribuzione (vedi la raccomandazione sulla versione di solc (opens in a new tab) di Slither).
  • Non usare l'assembly inline. L'assembly richiede esperienza con l'EVM. Non scrivere codice EVM se non hai padroneggiato lo yellow paper.

Linee guida per la distribuzione

Una volta che il contratto è stato sviluppato e distribuito:

  • Monitora i tuoi contratti. Osserva i log e tieniti pronto a reagire in caso di compromissione del contratto o del portafoglio.
  • Aggiungi le tue informazioni di contatto a blockchain-security-contacts (opens in a new tab). Questo elenco aiuta terze parti a contattarti se viene scoperta una falla di sicurezza.
  • Metti in sicurezza i portafogli degli utenti privilegiati. Segui le nostre migliori pratiche (opens in a new tab) se archivi le chiavi in portafogli hardware.
  • Prepara un piano di risposta agli incidenti. Considera che i tuoi smart contract possono essere compromessi. Anche se i tuoi contratti sono privi di bug, un utente malintenzionato potrebbe prendere il controllo delle chiavi del proprietario del contratto.