Ethereums smarta kontraktssäkerhetsrekommendationer

blogg 1NyheterUtvecklareFöretagBlockchain förklaradeHändelser och konferenserPressNyhetsbrev

Prenumerera på vårt nyhetsbrev.

E-postadress

Vi respekterar din integritet

HemBlogBlockchain utveckling

Ethereums smarta kontraktssäkerhetsrekommendationer

Från hur man hanterar externa samtal till åtagandescheman, här är 10+ smarta kontraktssäkerhetsmönster att följa när du bygger på Ethereum. Av ConsenSys 10 juli 2020 Upplagt den 10 juli 2020

Ethereums smarta kontraktssäkerhetsrekommendationer

Som vi behandlade i Smart Contract Security Mindset håller en vaksam Ethereum-utvecklare alltid fem principer i åtanke:

  • Förbered dig på misslyckande
  • Utrullning försiktigt
  • Håll kontrakten enkla
  • Hålla sig uppdaterad
  • Var medveten om EVM: s egenart

I det här inlägget kommer vi att dyka in i EVM: s idiosynkrasier och gå igenom en lista över mönster som du bör följa när du utvecklar ett smart kontraktssystem på Ethereum. Denna bit är främst för mellanliggande Ethereum-utvecklare. Om du fortfarande är i de tidiga stadierna av utforskningen, kolla in ConsenSys Academys on-demand blockchain-utvecklarprogram. 

Okej, låt oss dyka in.

Externa samtal

Var försiktig när du ringer externa samtal

Samtal till otillförlitliga smarta kontrakt kan medföra flera oväntade risker eller fel. Externa samtal kan utföra skadlig kod i det avtalet eller något annat kontrakt som det beror på. Behandla därför varje externt samtal som en potentiell säkerhetsrisk. Om det inte är möjligt eller inte önskvärt att ta bort externa samtal, använd rekommendationerna i resten av detta avsnitt för att minimera risken.

Markera otillförlitliga kontrakt

När du interagerar med externa kontrakt, namnge dina variabler, metoder och kontraktsgränssnitt på ett sätt som gör det tydligt att interagera med dem är potentiellt osäkra. Detta gäller för dina egna funktioner som anropar externa kontrakt.

// dålig Bank.withdraw (100); // Oklart om betrodda eller opålitliga funktioner makeWithdrawal (uint belopp) {// Är inte klart att denna funktion är potentiellt osäker Bank.withdraw (belopp); } // bra UntrustedBank.withdraw (100); // otillförlitligt externt samtal TrustedBank.withdraw (100); // externt men pålitligt bankavtal som upprätthålls av XYZ Corp-funktionen makeUntrustedWithdrawal (uint amount) {UntrustedBank.withdraw (amount); } Kodspråk: PHP (php)

Undvik tillståndsförändringar efter externa samtal

Oavsett om du använder råa samtal (av formen someAddress.call ()) eller kontraktssamtal (av formuläret ExternalContract.someMethod ()), antar att skadlig kod kan köras. Även om ExternalContract inte är skadligt kan skadlig kod köras av alla kontrakt som den anropar.

En speciell fara är att skadlig kod kan kapa kontrollflödet och leda till sårbarheter på grund av återinträde. (Ser Återinträde för en mer detaljerad diskussion om detta problem).

Om du ringer till ett otillförlitligt externt kontrakt, undvik tillståndsändringar efter samtalet. Detta mönster kallas också ibland kontroll-effekter-interaktionsmönster.

Ser SWC-107

Använd inte transfer () eller skicka ().

.transfer () och.send () vidarebefordra exakt 2300 gas till mottagaren. Målet med detta hårdkodade gasstipendium var att förhindra sårbarheter för återinträde, men detta är bara vettigt under antagandet att gaskostnaderna är konstanta. EIP 1884, som var en del av Istanbul hårdgaffel, ökade bensinkostnaderna för SLOAD-verksamheten. Detta orsakade att ett avtals reservfunktion kostade mer än 2300 gas. Vi rekommenderar att du slutar använda.transfer () och.send () och istället använda.call ().

// dåligt kontrakt Sårbart {funktion tar ut (belopp uint256) externt {// Detta vidarebefordrar 2300 gas, vilket kanske inte räcker om mottagaren // är ett kontrakt och gaskostnaderna ändras. msg.sender.transfer (belopp); }} // bra kontrakt Fixat {funktion uttag (belopp uint256) externt {// Detta vidarebefordrar all tillgänglig gas. Var noga med att kontrollera returvärdet! (bool framgång,) = msg.sender.call.value (belopp) (""); kräver (framgång, "Överföringen misslyckades."); }} Kodspråk: JavaScript (javascript)

Observera att.call () inte gör något för att mildra återintensitetsattacker, så andra försiktighetsåtgärder måste vidtas. För att förhindra återinträdesattacker, använd kontroll-effekter-interaktionsmönster.

Hantera fel i externa samtal

Solidity erbjuder samtalsmetoder på låg nivå som fungerar på råa adresser: address.call (), address.callcode (), address.delegatecall () och address.send (). Dessa metoder på låg nivå kastar aldrig ett undantag, men kommer att returnera falskt om samtalet stöter på ett undantag. Å andra sidan kommer kontraktssamtal (t.ex. ExternalContract.doSomething ()) automatiskt att sprida ett kast (till exempel kommer ExternalContract.doSomething () också att kasta om doSomething () kastar).

Om du väljer att använda samtalsmetoder på låg nivå, se till att hantera möjligheten att samtalet misslyckas genom att kontrollera returvärdet.

// dålig someAddress.send (55); someAddress.call.value (55) (""); // detta är dubbelt farligt, eftersom det vidarebefordrar all återstående gas och inte söker efter resultat someAddress.call.value (100) (bytes4 (sha3 ("deposition()"))); // om insättning ger ett undantag, kommer det råa samtalet () bara att returnera falskt och transaktionen kommer INTE att återställas // bra (bool-framgång,) = someAddress.call.value (55) (""); if (! success) {// hantera felkod} ExternalContract (someAddress) .deposit.value (100) (); Kodspråk: JavaScript (javascript)

Ser SWC-104

Favorittryck för externa samtal

Externa samtal kan misslyckas av misstag eller medvetet. För att minimera skador som orsakas av sådana fel är det ofta bättre att isolera varje externt samtal i sin egen transaktion som kan initieras av mottagaren av samtalet. Detta är särskilt relevant för betalningar, där det är bättre att låta användare ta ut medel snarare än att driva pengar automatiskt till dem. (Detta minskar också risken för problem med gasgränsen.) Undvik att kombinera flera eteröverföringar i en enda transaktion.

// dålig kontraktauktion {adress högsta budgivare; inte högsta bud; funktionsbud () betalas {kräver (msg.värde >= högsta bud); if (högsta budgivare! = adress (0)) {(bool framgång,) = högsta budgivare.samtal.värde (högsta bud) (""); kräver (framgång); // om det här samtalet konsekvent misslyckas, kan ingen annan bjuda} bestBidder = msg.sender; högsta bud = msg.värde; }} // bra auktionsavtal {adress högsta budgivare; inte högsta bud; mapping (adress => uint) återbetalningar; funktionsbud () betalas externt {kräver (msg.värde >= högsta bud); if (högsta budgivare! = adress (0)) {återbetalar [högsta budgivare] + = högsta bud; // registrera återbetalningen som den här användaren kan göra anspråk på} högsta budgivare = msg.sändare; högsta bud = msg.värde; } funktion pullRefund () extern {uint refund = refunds [msg.sender]; återbetalningar [msg.sender] = 0; (bool framgång,) = msg.sender.call.value (återbetalning) (""); kräver (framgång); }} Kodspråk: JavaScript (javascript)

Ser SWC-128

Delegera inte samtal till otillförlitlig kod

Delegeringssamtalet anropar funktioner från andra kontrakt som om de tillhör uppringarkontraktet. Således kan callee ändra tillståndet för den anropande adressen. Detta kan vara osäkert. Ett exempel nedan visar hur användning av delegatecall kan leda till förstörelse av kontraktet och förlust av balans.

kontrakt Destructor {funktion doWork () extern {selfdestruct (0); }} kontraktsarbetare {funktion doWork (adress _internalWorker) offentlig {// osäker _internalWorker.delegatecall (bytes4 (keccak256 ("doWork ()"))); }} Kodspråk: JavaScript (javascript)

Om Worker.doWork () anropas med adressen till det distribuerade Destructor-avtalet som ett argument, kommer Worker-kontraktet att förstöra sig själv. Delegera exekvering endast till betrodda kontrakt och aldrig till en användaradress.

Varning

Antag inte att kontrakt skapas utan saldo. En angripare kan skicka eter till adressen till ett kontrakt innan det skapas. Kontrakt bör inte anta att dess ursprungliga tillstånd innehåller en nollbalans. Ser nummer 61 för mer detaljer.

Ser SWC-112

Kom ihåg att eter kan skickas till ett konto med våld

Akta dig för att koda en invariant som strikt kontrollerar saldot i ett kontrakt.

En angripare kan med våld skicka eter till valfritt konto. Detta kan inte förhindras (inte ens med en reservfunktion som gör en återställning ()).

Angriparen kan göra detta genom att skapa ett kontrakt, finansiera det med 1 wei och åberopa självförstörelse (victimAddress). Ingen kod åberopas i victimAddress, så det kan inte förhindras. Detta gäller också för blockbelöning som skickas till gruvarbetarens adress, vilket kan vara vilken godtycklig adress som helst.

Eftersom kontraktsadresser kan beräknas i förväg kan eter också skickas till en adress innan kontraktet distribueras.

Ser SWC-132

Kom ihåg att data i kedjan är offentliga

Många ansökningar kräver att inlämnade uppgifter är privata fram till någon tidpunkt för att kunna fungera. Spel (t.ex. rock-paper-sax i kedjan) och auktionsmekanismer (t.ex. förseglat bud) Vickrey-auktioner) är två huvudkategorier av exempel. Om du bygger en applikation där sekretess är ett problem, se till att du undviker att kräva att användare publicerar information för tidigt. Den bästa strategin är att använda åtagandesystem med separata faser: begå först att använda värdenas hash och i en senare fas avslöja värdena.

Exempel:

  • I stenpapper sax, kräva att båda spelarna skickar in en hash av deras avsedda drag först och sedan kräver att båda spelarna skickar in sitt drag; om det inlämnade flyttet inte stämmer med haschen, kasta ut det.
  • I en auktion, kräva att spelare skickar in en hash av sitt budvärde i en inledande fas (tillsammans med en insättning som är större än deras budvärde) och sedan skickar in sitt auktionsbudvärde i den andra fasen.
  • När du utvecklar en applikation som är beroende av en slumptalsgenerator bör beställningen alltid vara (1) spelare skickar drag, (2) genererade slumpmässiga nummer, (3) spelare betalas ut. Många människor forskar aktivt om slumptalsgeneratorer; nuvarande klassens bästa lösningar inkluderar Bitcoin-blockrubriker (verifieras genom http://btcrelay.org), hash-commit-reveal-scheman (dvs. en part genererar ett nummer, publicerar sin hash för att “commit” till värdet och avslöjar sedan värdet senare) och RANDAO. Eftersom Ethereum är ett deterministiskt protokoll kan du inte använda någon variabel i protokollet som ett oförutsägbart slumptal. Tänk också på att gruvarbetare i viss utsträckning kontrollerar värdet block.blockhash ()*.

Akta dig för möjligheten att vissa deltagare kan “släppa offline” och inte återvända

Gör inte återbetalnings- eller anspråksprocesser beroende av att en viss part utför en viss åtgärd utan något annat sätt att få ut pengarna. Till exempel i ett rock-paper-saxspel är ett vanligt misstag att inte göra en utbetalning förrän båda spelarna lämnar in sina drag; en skadlig spelare kan dock “bedröva” den andra genom att helt enkelt aldrig lämna in sitt drag – i själva verket, om en spelare ser den andra spelarens avslöjade drag och bestämmer att de förlorade, har de ingen anledning att lämna in sitt eget drag alls. Denna fråga kan också uppstå i samband med statlig kanalavveckling. När sådana situationer är ett problem, (1) ger ett sätt att kringgå icke-deltagande deltagare, kanske genom en tidsgräns, och (2) överväga att lägga till ett ytterligare ekonomiskt incitament för deltagarna att skicka information i alla situationer där de befinner sig ska göra det.

Se upp för negation av det mest negativa signerade heltalet

Soliditet ger flera typer att arbeta med signerade heltal. Som i de flesta programmeringsspråk kan ett undertecknat heltal med N-bitar i soliditet representera värden från -2 ^ (N-1) till 2 ^ (N-1) -1. Detta innebär att det inte finns någon positiv ekvivalent för MIN_INT. Negation implementeras för att hitta de två komplementet till ett tal, så negationen av det mest negativa talet kommer att resultera i samma antal. Detta gäller för alla signerade heltalstyper i soliditet (int8, int16,…, int256).

kontrakt Negation {funktion negate8 (int8 _i) offentlig ren avkastning (int8) {return -_i; } funktion negate16 (int16 _i) offentlig ren avkastning (int16) {return -_i; } int8 public a = negate8 (-128); // -128 int16 public b = negate16 (-128); // 128 int16 public c = negate16 (-32768); // -32768} Kodspråk: PHP (php)

Ett sätt att hantera detta är att kontrollera värdet på en variabel före negation och kasta om den är lika med MIN_INT. Ett annat alternativ är att se till att det mest negativa talet aldrig uppnås genom att använda en typ med högre kapacitet (t.ex. int32 istället för int16).

Ett liknande problem med int-typer uppstår när MIN_INT multipliceras eller delas med -1.

Är din blockchain-kod säker? 

Vi hoppas att dessa rekommendationer har varit till hjälp. Om du och ditt team förbereder för lansering eller till och med i början av utvecklingslivscykeln och behöver dina smarta kontraktsförnuftskontroll är du välkommen att kontakta vårt team av säkerhetsingenjörer på ConsenSys Diligence. Vi är här för att hjälpa dig att starta och underhålla dina Ethereum-applikationer med 100% förtroende. 

Boka en säkerhetskontroll

Boka en 1-dagars recension med vårt team av blockchain-säkerhetsexperter. Boka din idag SäkerhetSmarta kontraktNyhetsbrevPrenumerera på vårt nyhetsbrev för de senaste Ethereum-nyheterna, företagslösningar, utvecklarresurser och mer.E-postadressExklusivt innehållHur man bygger en framgångsrik Blockchain-produktWebinar

Hur man bygger en framgångsrik Blockchain-produkt

Hur man ställer in och kör en Ethereum-nodWebinar

Hur man ställer in och kör en Ethereum-nod

Hur man bygger ditt eget Ethereum APIWebinar

Hur man bygger ditt eget Ethereum API

Hur man skapar en social tokenWebinar

Hur man skapar en social token

Använda säkerhetsverktyg i Smart Contract DevelopmentWebinar

Använda säkerhetsverktyg i Smart Contract Development

Framtiden för finansiella digitala tillgångar och DeFiWebinar

Framtiden för ekonomi: digitala tillgångar och deFi

Mike Owergreen Administrator
Sorry! The Author has not filled his profile.
follow me
Like this post? Please share to your friends:
map