Přejít na hlavní obsah

Pokyny pro bezpečnost chytrých kontraktů

Solidity
chytré kontrakty
bezpečnost
Středně pokročilý
Trailofbits
6. září 2020
4 minut čtení

Dodržujte tato obecná doporučení pro tvorbu bezpečnějších chytrých kontraktů.

Pokyny pro návrh

Návrh kontraktu by měl být prodiskutován předem, ještě před napsáním jediného řádku kódu.

Dokumentace a specifikace

Dokumentace může být psána na různých úrovních a měla by být aktualizována během implementace kontraktů:

  • Popis systému v běžném jazyce, který popisuje, co kontrakty dělají, a jakékoli předpoklady o kódové základně.
  • Schémata a architektonické diagramy, včetně interakcí kontraktů a stavového automatu systému. S generováním těchto schémat mohou pomoci tiskárny Slither (opens in a new tab).
  • Důkladná dokumentace kódu, pro Solidity lze použít formát NatSpec (opens in a new tab).

Výpočty onchain vs offchain

  • Udržujte co nejvíce kódu offchain. Udržujte onchain vrstvu malou. Předzpracujte data pomocí kódu offchain takovým způsobem, aby bylo ověření onchain jednoduché. Potřebujete seřazený seznam? Seřaďte seznam offchain a onchain pouze zkontrolujte jeho pořadí.

Aktualizovatelnost

Různá řešení aktualizovatelnosti jsme probírali v našem článku na blogu (opens in a new tab). Před napsáním jakéhokoli kódu se vědomě rozhodněte, zda budete podporovat aktualizovatelnost, či nikoli. Toto rozhodnutí ovlivní, jak budete strukturovat svůj kód. Obecně doporučujeme:

  • Upřednostnit migraci kontraktů (opens in a new tab) před aktualizovatelností. Migrační systémy mají mnoho stejných výhod jako ty aktualizovatelné, ale bez jejich nevýhod.
  • Použít vzor oddělení dat (data separation) místo vzoru delegatecallproxy. Pokud má váš projekt jasné oddělení abstrakce, aktualizovatelnost pomocí oddělení dat bude vyžadovat pouze několik úprav. Vzor delegatecallproxy vyžaduje odborné znalosti EVM a je velmi náchylný k chybám.
  • Zdokumentovat postup migrace/aktualizace před nasazením. Pokud musíte reagovat ve stresu bez jakýchkoli pokynů, uděláte chyby. Napište si postup, kterým se budete řídit, předem. Měl by obsahovat:
    • Volání, která inicializují nové kontrakty
    • Kde jsou uloženy klíče a jak k nim získat přístup
    • Jak zkontrolovat nasazení! Vyviňte a otestujte skript po nasazení (post-deployment script).

Pokyny pro implementaci

Usilujte o jednoduchost. Vždy použijte to nejjednodušší řešení, které vyhovuje vašemu účelu. Kterýkoli člen vašeho týmu by měl být schopen vašemu řešení porozumět.

Skládání funkcí

Architektura vaší kódové základny by měla usnadňovat revizi kódu. Vyhněte se architektonickým rozhodnutím, která snižují schopnost uvažovat o jeho správnosti.

  • Rozdělte logiku svého systému, ať už prostřednictvím více kontraktů, nebo seskupením podobných funkcí (například autentizace, aritmetika, ...).
  • Pište malé funkce s jasným účelem. To usnadní revizi a umožní testování jednotlivých komponent.

Dědičnost

  • Udržujte dědičnost zvládnutelnou. Dědičnost by se měla používat k rozdělení logiky, váš projekt by se však měl snažit minimalizovat hloubku a šířku stromu dědičnosti.
  • Použijte tiskárnu dědičnosti (inheritance printer) (opens in a new tab) nástroje Slither ke kontrole hierarchie kontraktů. Tiskárna dědičnosti vám pomůže zkontrolovat velikost hierarchie.

Události

  • Logujte všechny klíčové operace. Události pomohou s laděním kontraktu během vývoje a s jeho monitorováním po nasazení.

Vyhněte se známým úskalím

Závislosti

  • Používejte dobře otestované knihovny. Importování kódu z dobře otestovaných knihoven sníží pravděpodobnost, že napíšete chybový kód. Pokud chcete napsat kontrakt ERC-20, použijte OpenZeppelin (opens in a new tab).
  • Používejte správce závislostí; vyhněte se kopírování a vkládání kódu. Pokud spoléháte na externí zdroj, musíte jej udržovat aktuální s původním zdrojem.

Testování a ověřování

  • Pište důkladné jednotkové testy (unit testy). Rozsáhlá sada testů je pro tvorbu vysoce kvalitního softwaru klíčová.
  • Pište vlastní kontroly a vlastnosti pro Slither (opens in a new tab), Echidnu (opens in a new tab) a Manticore (opens in a new tab). Automatizované nástroje pomohou zajistit bezpečnost vašeho kontraktu. Projděte si zbytek tohoto průvodce, abyste se naučili, jak psát efektivní kontroly a vlastnosti.
  • Používejte crytic.io (opens in a new tab). Crytic se integruje s GitHubem, poskytuje přístup k soukromým detektorům nástroje Slither a spouští vlastní kontroly vlastností z Echidny.

Solidity

  • Upřednostňujte Solidity 0.5 před 0.4 a 0.6. Podle našeho názoru je Solidity 0.5 bezpečnější a má lepší vestavěné postupy než 0.4. Solidity 0.6 se ukázalo jako příliš nestabilní pro produkci a potřebuje čas na dozrání.
  • Ke kompilaci používejte stabilní verzi; ke kontrole varování používejte nejnovější verzi. Zkontrolujte, zda váš kód nemá s nejnovější verzí kompilátoru žádné hlášené problémy. Solidity má však rychlý cyklus vydávání a historii chyb v kompilátoru, proto nedoporučujeme nejnovější verzi pro nasazení (viz doporučení verze solc (opens in a new tab) od nástroje Slither).
  • Nepoužívejte inline assembly. Assembly vyžaduje odborné znalosti EVM. Nepište kód pro EVM, pokud jste neovládli yellow paper.

Pokyny pro nasazení

Jakmile je kontrakt vyvinut a nasazen:

  • Monitorujte své kontrakty. Sledujte logy a buďte připraveni reagovat v případě kompromitování kontraktu nebo peněženky.
  • Přidejte své kontaktní údaje do blockchain-security-contacts (opens in a new tab). Tento seznam pomáhá třetím stranám kontaktovat vás v případě objevení bezpečnostní chyby.
  • Zabezpečte peněženky privilegovaných uživatelů. Pokud ukládáte klíče v hardwarových peněženkách, řiďte se našimi osvědčenými postupy (opens in a new tab).
  • Mějte plán reakce na incidenty. Počítejte s tím, že vaše chytré kontrakty mohou být kompromitovány. I když jsou vaše kontrakty bez chyb, útočník může získat kontrolu nad klíči vlastníka kontraktu.