Hur man granskar ett smart kontrakt

En omfattande guide om mätning Smart kontraktssäkerhet.

Medan ökningen av blockchain ger en unik möjlighet till distribuerad konsensus, kommer Smart Contract-applikationer med unika säkerhetsproblem som historiskt har lett till miljontals USD i förluster, såsom de ökända DAO Attack. För att mildra dessa risker är det nödvändigt att genomföra säkerhetsrevisioner på smarta kontrakt. I den här guiden beskriver vi noggrant olika Smart Contract-attacker och granskningsprocessen som man måste genomföra för att säkerställa säkerhet, på ett sätt som överensstämmer med den senaste utvecklingen och med inspiration från en mängd olika trovärdiga källor. 

En Smart Contract-granskning är i grunden densamma som en vanlig kodgranskning – som noggrant undersöker kod för att hitta säkerhetsfel och sårbarheter innan koden publiceras offentligt. Det är som att testa en bro innan den öppnas för allmänheten. I båda fallen har byggare ansvar för säkerheten och säkerheten för sina produkter. Eftersom blockkedjan i huvudsak är en replikerad, endast bifogad länkad “lista” över märketräd (det är därför oföränderlig), och smarta kontrakt är självkörande, är det viktigt att hitta eventuella sårbarheter i koden före lansering.

Hur man granskar ett smart kontrakt

 Vilka typer av smarta kontraktsattacker finns det?

Detta avsnitt diskuterar kända attacker som du bör vara medveten om, följt av specifika steg du kan vidta för att hitta sådana attacker i en revision.

Tävlingsförhållanden är ett allmänt systems beteende där händelser inte inträffar i den avsedda ordningen. I smarta kontrakt kan tävlingsvillkor uppstå genom att anropa externa kontrakt som tar över kontrollflödet.

Återinträde beskriver en version av Race Villkor där någon funktion anropas upprepade gånger innan den första funktionsanropet är slutfört. Till exempel en av DAO-attackfelen berodde på olika anrop av funktioner som interagerar på oavsiktliga sätt. Nyckellösningen är att blockera samtidiga samtal från att hända i vissa funktioner, särskilt granska externa samtal.

Exempel på ett kontrakt med återinträdesfelet:

ReentrancyVulnerability {contract)

funktion återkalla () {

uint transferAmount = 10 eter;

om (! msg.sender.call.value (transferAmount) ()) kast;

}

funktionsdeposition () betalas {} // gör kontraktet betalbart och skickar eter

}

Ovan är linjen som är markerad med rött ett externt samtal, som i allmänhet bör undvikas. Funktionen återkalla () överför 10 eter till msg.sender. Än så länge är allt bra. Mottagaren kan dock ringa upp funktionen flera gånger med en rekursiv sändningsutnyttjande, som visas nedan.

Anta att ovanstående kontrakt finns i en ReentrancyVulnerability.sol-fil och angriparen skapar en Hacker.sol-fil med ett Hacker-kontrakt som utnyttjar det externa samtalet. Ett sådant kontrakt kan användas för att “testa” potentiella sårbarheter för återinträde:

kontrakt Hacker {

Återintag Sårbarhet r;

inte allmänna räkningar;

händelse LogFallback (uint c, uint balance);

funktionsattacker (adress sårbar) {

r = ReentrancyVulnerability (sårbar);

}

funktionsattack () {

r.withdraw ();

}

funktion () betalas {

räkna ++;

LogFallback (räkna, detta. Balans);

if (räkna < 10) {

r.withdraw ();

}

}

I Hacker.sol definieras två primära funktioner (förutom en byte av namn). Den första är en återkallningsfunktion som betalbar () som kallar metoden ReentrancyVulnerability contract pull (), skickar 10 eter till Hacker, utlöser den andra funktionen: en funktion () betalbar {}, som är en reservfunktion (används för att fånga överflödig eter ).

En händelse LogFallback (uint v, uint balance); definieras som utlöses när reservfunktionen som definieras ovan anropas. Denna händelse körs genom ett if-uttalande med en räknare för att fungera som en slinga som stoppar funktionen vid 10 samtal för att förhindra eteråterföring. Slutligen anropas metoden Hacker’s pull () igen. Detta är möjligt eftersom innan den ursprungliga återkallningsmetoden () i betalbar () är klar, återkallas återkallande () tills if-uttalandet är uppfyllt senast och räknarvillkoret är uppfyllt.

Återinträde är ett symptom på ett problem, inte roten till det, så var noga med att analysera var externa funktioner används, snarare än att försöka stoppa återinträde direkt vid en funktion. Vad detta innebär är att slutföra allt internt arbete innan du anropar den externa funktionen.

Takeaway: Minimera extern kod eller på annat sätt slutföra allt internt arbete före externa samtal.

Tvärfunktionella loppförhållanden beskriva en liknande attack av två funktioner som delar samma tillstånd, med samma lösningar. Ett exempel är en angripare som externt anropar överföring () innan användarbalansen har ställts till 0, eller även om angriparen redan har fått uttaget:

funktionsöverföring (adress till, uint belopp) {

överföring sker här

}

funktion pullBalance () public {

uint amountToWithdraw = userBalances [msg.sender];

kräver (msg.sender.call.value (amountToWithdraw) ());

userBalances [msg.sender] = 0;

}

I ovanstående kod kan hackaren ringa överföring () när den röda linjen i återkallning () körs eller när det externa samtalet görs. Som du kan se är userBalance bara inställt på 0 efteråt, så hackaren kan överföra tokens även om tillbakadragandet har gjorts.

Transaktionsbeställningsberoende (TOD) / Front Running är ännu ett rasvillkor, men den här gången i samband med manipulationer av transaktionsorder inom ett block. Detta gäller att transaktionen ligger i en mempool under en kort tid. Front Running tillåter en användare att dra nytta av en manipulerad transaktionsorder på bekostnad av en annan användare.

  • Ett tillstånd som kan tillåta Front Running är Tidsstämpelberoende, så du måste granska användningen av tidsstämpeln, särskilt i fall där transaktionstiden är ekonomiskt viktig – till exempel i ett vadslagningskontrakt. Ethereums tidsstämpel kopplas bort från en synkroniserad global klocka, och denna avvikelse kan utnyttjas av gruvarbetare.
  • Ett annat villkor är Integer Overflow och Underflow, varigenom ett uint-värde som når maximala cirklar till noll eller ett uint-värde mindre än noll sätts till sitt maximala. Heltalsflöden och underflöden kan detekteras av verktyg som Mythril.

        

Kodexemplet för överflöden och underflöden är väldigt enkelt:

uint public c = a + b;

En angripare kan sedan subtrahera för underflöde eller lägga till för överflöde:

funktionsunderflöde () offentligt {

c – = 2 ** 256-1;

}

function overflow () public {

c + = 2 ** 256-1;

}

En annan form av attack aktiveras av förmågan att med våld skicka Ether till ett kontrakt, för att säkerställa att det inte finns något försök i logiken att begränsa finansieringen till ett kontrakt, eftersom denna attack skulle besegra den logiken.

Vilken kod som helst med följande logik är en sårbarhet för ovanstående:

kräver (detta. balans > 0); // notera att 0 kan vara vilket nummer som helst

För att förhindra att sådana attacker startas framgångsrikt på koden du analyserar, bör granskningsprocessen ta en teknisk metod – noggrann verifiering med bakgrund av teori och praktik, samt verktygstillämpning.

 Stegen för en fullständig smart kontraktsrevision

Sårbarheter som möjliggör ovannämnda attacker, liksom andra fel och säkerhetsproblem, skulle hittas med följande granskningsprocess, som tar inspiration från Consensys bästa praxis, de HashEx granskningsram, och offentliga revisioner för att skapa en mer omfattande struktur:

     0. Se till att granskningen kommer att slutföras på ett distribuerat smart kontrakt2: din  

           granskning bör utföras på en släppkandidat (RC) eller den slutliga Smart

           Kontraktsfas innan offentliggörande, eftersom det är det som är närmast slutanvändaren

           produkt.

  1. Ge en juridisk ansvarsfriskrivning: Observera att syftet med revisionen är att främja diskussioner grundade på säkerhetsprinciper snarare än att ge några garantier.

Till exempel: “Informationen som visas i denna revision är endast avsedd för allmänna diskussioner och är inte avsedd att ge rättssäkerhetsgarantier till någon individ eller enhet.”

  1. Förklara vem du är: Förklara din auktoritet i rymden, eller varför du kan lita på att du utför en noggrann analys och sedan säkerhetskopiera den med en stark granskning.
  2. Förklara din granskningsprocess: Beskriv de smarta kontrakt som du granskar och processen du kommer att använda, ur ett säkerhetsperspektiv.
  3. Utför sårbarhetstester för attacker: Analysera om någon av de relevanta attackerna som dokumenterats ovan kunde lyckas mot kontraktet.
  4. Detaljerade sårbarheter och bekymmer: I det här steget diskuterar du kritiska sårbarheter på medium och låg svårighetsgrad, tillsammans med förslag på korrigeringar. Det kan finnas områden som inte är omedelbart utsatta, men en potentiell oro – notera även dessa.
  5. Analysera kontraktets komplexitet: Komplexitet ökar sannolikheten för fel, så notera komplex kontraktlogik, icke-modulerad kod, egna verktyg och kod och prestanda över tydlighet. Ingen av dessa är nödvändigtvis en röd flagga men bör undvikas när det är möjligt.
  6. Analysera felförberedelser: Hur skulle kontraktet reagera i händelse av misslyckanden, till exempel en bugg eller sårbarhet? Kontrollera att kontraktet skulle pausa och att pengar i riskzonen skulle hanteras.
  7. Analysera kodvaluta: Uppdateras alla bibliotek och verktyg till de senaste versionerna? Senaste verktygsversionerna kan komma med sårbarhetsuppdateringar, så att använda äldre versioner är en onödig och lätt förebyggbar risk.
  8. Analys av återanvänd Versus Duplicated Code: Duplicerad kod från tidigare distribuerade, säkerhetsbevisade kontrakt kräver ingen noggrann analys. Återanvänd kod som inte har granskats tidigare måste dock granskas kraftigt och bör inte användas om en väl testad och tidigare distribuerad version finns tillgänglig.
  9.  Analysera externa samtal
  1. Är statliga förändringar efter externa samtal undvikna? Externa samtal kan manipulera kontrollflödet, så var noga med att slutföra alla interna samtal först.
  2. Är otillförlitliga kontrakt märkta? Externa kontrakt bör vara tydligt markerade för att förmedla att kodinteraktioner är potentiellt osäkra. Detta inkluderar namngivningskonventioner, till exempel UntrustedSender i motsats till Sender.
  3. Hanteras fel i externa samtal korrekt? Kontraktssamtal sprider automatiskt ett kast om ett undantag påträffas och utan att hantera denna möjlighet (genom att kontrollera returvärdet) kommer kontraktet att misslyckas.
  4. Gör externa samtal för push-pull? Se till att externa samtal är isolerade i sina egna transaktioner för att minimera konsekvenserna av externt samtalsfel.
  1.  Initial balansanalys: Gör koden antaganden om att kontraktet börjar med noll balans? En avtalsadress kan ta emot wei innan kontraktet skapas, så det bör inte finnas ett initialt balansantagande.
  2.  Analysera säkerheten för on-chain data: Se till att den tid då vissa on-chain data visas inte är avgörande för kontraktsfunktionaliteten, eftersom dessa data är offentliga och fel ordning kan gynna en part framför en annan (till exempel i ett klipp-pappers-saxspel).
  3.  Analysera N-partyavtal: Är det OK om deltagarna tappar och inte återvänder? Denna möjlighet måste beaktas.
  4.  Fasthetsspecifik
  1. Tvingas invandrarna till? Ett misslyckat påstående utlöser en påståendevakt. Ett påstående () bör användas vid hantering av invarianter, såsom påstå (detta. Balans >= totalförsörjning);
  2. Är heltal uppdelad? Helt enkelt avrundar alla heltal upp till närmaste heltal i soliditet. Om detta är ett problem, använd istället en multiplikator.
  3. Vad händer om Ether skickas med våld? Eftersom ETH kan skickas med våld till en adress, notera eventuell oförändrad kodning som kontrollerar saldot i ett kontrakt och hur tvingat ETH-beteende kan påverka koden.
  4. Är tx. Ursprung Begagnade? tx.origin bör aldrig användas för auktorisering, eftersom den innehåller din adress, så ett annat kontrakt kan ringa ditt kontrakt och bli auktoriserat (om tx.origin används, rekommendera att du använder msg.sender () istället).
  5. Beroende på tidsstämpel: Som diskuteras i avsnittet Kända attacker är Ethereum-tidsstämpeln kopplad från en synkroniserad global klocka, och denna avvikelse kan utnyttjas av gruvarbetare, så tidsstämpelberoende bör minimeras.
  1.  Erbjud nästa steg: Föreslå korrigeringar av de sårbarheter som hittats och steg framåt. Om dessa fixades skulle kontrakten vara säker för mainnet-användning?

Fler granskning och fel exempel

Här hittar vi insikter från historiska exempel på revisioner och kodavsnitt som du kan använda för dina egna Smart Contract-revisioner. Det finns ett ökande antal enheter i granskningsutrymmet för Smart Contract, med ramar som sträcker sig från kommentarfokuserade till testfokuserade, både med styrkor och svagheter.

För ett exempel på “unchecked-send” -felet erbjuder Hacking, Distribuerad-bloggen det här kodavsnittet:

if (gameHasEnded && !(prizePaidOut)) {

vinnare. skicka (1000); // skicka ett pris till vinnaren

prizePaidOut = True;

}

Som diskuteras i avsnittet om granskningssteg bör användningen av send () alltid undersökas noggrant. I det här fallet kan metoden send () misslyckas, vilket gör att spelvinnaren inte kan betala. Liknande sårbarheter kan finnas för ett användningsfall som en auktion där potentiellt stora fonder är i riskzonen.

Enligt Ethereum-dokumentation, detta fel kan inträffa “Om samtalsstapeldjupet är 1024 (detta kan alltid tvingas av den som ringer) och det misslyckas också om mottagaren tar slut på bensin.” Dokumentationen erbjuder lösningen till “Kontrollera alltid returvärdet för skicka, eller ännu bättre: Använd ett mönster där mottagaren tar ut pengarna.”

Baserat på dokumentförslaget bär Hacking, Distribuerat denna lösning …

if (gameHasEnded && !(prizePaidOut)) {

konton [vinnare] + = 1000

konton [förlorare] + = 10

prizePaidOut = True;

}

uttag av funktion (belopp) {

if (konton [msg.sender] >= Belopp) {

msg.sender.send (belopp);

konton [msg.sender] – = belopp;

}

}

… varigenom koden omformas så att en misslyckad sändning endast påverkar en part i taget.

ConsenSys Best Practices-ramverk erbjuder många exempel på “bra och dålig kod”, som täcker kända attacker.

pragmasoliditet ^ 0.4.4; // dåligt

pragmasoliditet 0,4,4; // Bra

Det noteras till exempel ovan att pragmer ska vara låsta till en specifik kompilatorversion, för att undvika att kontrakt distribueras med en annan version, vilket kan ha en större risk för oupptäckta buggar.

uint256 konstant privat salt = block.timestamp; // varning

Koden för blockets tidsstämpel bör också vara en flagga för dig för att granska följande tidsstämpelanvändning.

Vi uppmuntrar dig att analysera de många andra exempel som rekommenderas av consenysus och bountyone

Granskningsverktyg som tillägg

En grundlig granskning kan innefatta tester tillsammans med dokumentation och användningsfall, vilket förklaras av användarnas beteende. I det här fallet bör man använda Behavior Driven Development (BDD) -metoder, vilket är jämförbart med Smart Contract-testaspekten av utveckling, men med fokus på säkerhet snarare än funktionalitet.

För att använda tryffel för granskning av Ethereum Smart Contracts använder du standard npm install -g tryffel för att installera ramverket och tryffel init för att skapa projektstrukturen (förutsatt att du tidigare har förvärvat node.js).

Denna process fokuserar på att skriva tester och utföra dem i ett testnätverk efter att ha importerat kontraktet och biblioteket för att kontrollera testförhållandena. Du kan använda den vanliga asserten () eller ett testramverk som Chai. Slutligen är det bara att testa de steg vi har byggt, som att kontrollera om det finns överflöden och underflöden, testa gränserna för funktioner, se till att returvärdena är korrekt formaterade och så vidare.

Många decentraliserade applikationer, som är centrerade kring smarta kontrakt, har implementerat en mängd olika programverktyg för att underlätta granskningspraxis. Dessa verktyg, såsom automatisk kodkontroll för sårbarheter, kan användas som ett komplement, men bör inte ersätta den formella granskningsprocessen. Ett alternativ, som tidigare nämnts, är Mythril, som kan användas för att upptäcka överflöden och underflöden. Ett annat verktyg är Etherscrape, används här att skrapa levande Ethereum-kontrakt för återinträdesfel när send () används. Det finns också decentraliserade revisionsplattformar som Bountyone som samlar företag och frilansrevisorer när verktyg inte räcker. 

Nästa steg

Beroende på svårighetsgraden av de sårbarheter som hittats rekommenderar du att du fokuserar på vissa aspekter av kontraktet för att förbättra. Du kan också rekommendera en bug bounty och fortsatt penetrationstestning som ett effektivt sätt att hitta andra buggar eller problem innan du startar, och erbjuder Ethereum Bounty som modell.

Ange att nya tillägg till kontrakt kommer att placera dem i oreviderad status, eftersom kodreformering kan införa nya sårbarheter. Slutligen skapa en kontaktpunkt för frågor – antingen i offentliga eller privata granskningar.

Slutsats

Granskningsskisserna som denna guide ger gäller smarta kontrakt i allmänhet, men är skräddarsydda för Ethereum-kontrakt, som är överlägset mest populära, och därmed transaktioner med flest medel, vilket ger dem den största risken för attack och med störst behov av revision.

Nu när du har verktygen, resurserna och kunskapen för att genomföra en Smart Contract-granskning – gå vidare för att förbättra säkerheten och trovärdigheten i blockchain-utrymmet. Om du är intresserad av att få betalt för att granska smarta kontrakt eller om du behöver ditt granskade smarta kontrakt, kolla in Bountyone.io

Vidare läsning

Eftersom blockchain-tekniken fortfarande är ett växande och snabbt växande område, finns det inga resurser för alltomfattande lösningar, så vi rekommenderar en mängd olika källor för att förbättra din förståelse för den här guiden.

01. “Bästa metoder för smart kontraktssäkerhet” förbi ConsenSys

02. “Granska det utplacerade smarta kontraktet, inte GitHub!” förbi ConsenSys

03. “Den ultimata guiden för att granska ett smart kontrakt + de farligaste attackerna i soliditet”  av Merunas Grincalaitis

04. ”Utveckla smarta kontrakt: bästa praxis för granskning av smarta kontrakt” förbi SMARTYM

05. “Betydelsen av revisioner och säker kodning för smarta kontrakt” på ETHNyheter

06. “Framåt med Ethereum Smart Contract Security” förbi Zeppelin Solutions

07. “EtherCamp’s Hacker Gold (HKG) public code audit” förbi Zeppelin Solutions

08. Stelnat: En fullständig revisionstjänst för smarta kontrakt

09. SmartDec: Verktygsstyrd Smart Contract Security Platform

10. Harvard Innovation Lab Audits på Experfy

11. Säkerhetsrevision utförd på Ethereum Classic Multisig Wallet förbi Dexaran

12. “Skanna levande Ethereum-kontrakt för buggen” Okontrollerad-skicka “ förbi Hacking, distribuerat

Mike Owergreen Administrator
Sorry! The Author has not filled his profile.
follow me