Vi har just sett hur ett litet kryphål leder till en ekonomisk förlust (av varierande storlek), på samma sätt som smarta kontrakt som utvecklats över soliditet är utsatta för olika kända och okända attacker. Utnyttjarna utnyttjar buggar och kryphål för att kika in i smarta kontrakt och manipulera dem för att utföra attacker. Här presenterar vi en omfattande lista över de fem vanligaste felen i programmeringsspråket Solidity.
På QuillAudits följer vi den adaptiva metoden för att få kärnan i varje hack och implementera sina lärdomar på framtida smarta kontrakt för att undvika eventuella hot.
Fel i programmeringsspråket soliditet
1. Avmarkerat externt samtal
Vi drar frågan i första hand för att den är en av de mest observerade fasthetsgroparna. Generellt sker att skicka eter till ett externt konto via överföra() fungera. Bortsett från detta är de två mest använda funktionerna för att ringa ett externt samtal; ring upp()och skicka (), här främst ring upp() funktionen används i stor utsträckning för att utföra mångsidiga externa samtal av utvecklarna.
Även om ring upp() och skicka () funktioner returnerar ett booleskt värde som anger om samtalet lyckades eller inte. Således i detta fall, om någon av funktionerna ring upp() or skicka () misslyckas med att utföra uppgiften kommer de att återgå med en falsk. Därför, om utvecklaren inte krysskontrollerar returvärdet, skulle det bli en fallgrop.
Sårbarheten
Tänk på exemplet nedan:
kontrakt Lotto {
boolpublic payedOut = false;
adressera allmän vinnare;
uintpublic winAmount;
// ... extra funktionalitet här
funktion sendToWinner () offentlig {
kräver (! payedOut);
winner.send (winAmount);
payedOut = true;
}
funktion pullLeftOver () public {
kräver (payedOut);
msg.sender.send (this.balance);
}
}
I det Lotto-liknande kontraktet ovan kan vi konstatera att a vinnare erhåller winAmount av eter som lämnar lite kvarvarande att dras tillbaka från någon extern agent.
Här finns fallgropen för kontraktet vid rad [11], där en sända används utan korsvalidering av svaret. I exemplet ovan, a vinnare vars transaktion misslyckas (antingen på grund av brist på gas eller om det är ett kontrakt som avsiktligt kastar in reservfunktionen), godkänner betalas ut som ska ställas in på sann oavsett om etertransaktionen var en framgång eller inte. I detta fall kan alla exploatörer dra tillbaka vinnarens vinster via dra ut vänster över funktion.
QuillAudits tillvägagångssätt
Vårt inbyggda team av utvecklare hanterar detta fel med hjälp av [överföra] funktion istället för [skicka] funktion, eftersom [överföring] återgår om extern transaktion återgår. Och om du använder [skicka], korsa alltid returvärdet.
En av de robusta metoderna som vi följer är att använda ett [tillbakadragningsmönster]. Här isolerar vi logiskt den externa sändningsfunktionaliteten från resten av kodbasen och placerar belastningen på potentiellt misslyckade transaktioner på slutanvändaren, eftersom han är den som kallar återkallningsfunktionen.
2. Återinträde
Ethereums smarta kontrakt ringer och använder koder från andra externa kontrakt, och för att genomföra detta måste kontrakten skicka externa samtal. Dessa externa samtal är sårbara och utsatta för attacker, en sådan attack ägde rum nyligen i fallet med DAO-hack.
Sårbarheten
Angripare utför sådana attacker när ett kontrakt skickar eter till en okänd adress. I det här fallet kan angriparen skapa ett kontrakt på en extern adress som har skadlig kod i reservfunktionen, och denna skadliga kod kommer att anropas när kontraktet skickar eter till den här adressen.
Faktum: Uttrycket "Reentrancy" har myntats från det faktum att när ett externt skadligt kontrakt anropar en funktion över det sårbara kontraktet och sedan "kör" sökkoden igen.
Tänk på exemplet nedan, det är ett Ethereum-valv som tillåter insättare att endast dra ut 1 eter per vecka.
kontrakt EtherStore {
uint256 offentligt tillbakadragandeLimit = 1 eter;
mapping (address => uint256) public lastWithdrawTime;
mapping (address => uint256) offentliga saldon;
funktion depositFunds () extern betalas {
balanserar [msg.sender] + = msg.value;
}
funktion pullFunds (uint256 _weiToWithdraw) public {
kräver (saldon [msg.sender]> = _weiToWithdraw);
// begränsa uttaget
kräver (_weiToWithdraw <= צוריקtagningsgräns);
// begränsa den tid som får återkallas
kräver (nu> = lastWithdrawTime [msg.sender] + 1 vecka);
kräver (msg.sender.call.value (_weiToWithdraw) ());
saldon [msg.sender] - = _weiToWithdraw;
lastWithdrawTime [msg.sender] = nu;
}
}
I ovanstående kontrakt har vi två offentliga funktioner, [depositionsfonder] och [uttagsfonder]. [DepositFunds] används för att öka avsändarens saldo, medan [återbetalningsfonder] anger det belopp som ska tas ut. I detta fall blir det en framgång om mängden som ska tas ut är mindre än 1 eter.
Fallgropen här ligger i rad [17] där överföringen av eter sker. Angriparen kan skapa ett skadligt kontrakt med [EtherStores] kontraktsadress som den enda konstruktörsparametern. Detta skulle göra [etherStore] till en offentlig variabel, därmed mer benägen att attackeras.
QuilllAudits strategi
Vi följer olika tekniker för att undvika potentiella sårbarheter för återinträde i smarta kontrakt. Det allra första och bästa möjliga sättet är att använda den inbyggda [transfer] -funktionen vid överföring av eter till något externt kontrakt.
För det andra är det viktigt att se till att alla logiska förändringar i tillståndsvariablerna ska göras innan etern skickas ut ur kontraktet. I [EtherStore] -exemplet bör rad [18] och [19] placeras före rad [17].
En tredje teknik kan också användas för att förhindra återuppringande samtal; genom införandet av en mutex. Det är ett tillägg av en statsvariabel som låser kontraktet under kodkörning.
3. Standardvisibiliteter
Det finns synlighetsspecifikationer för de funktioner vi använder i Solidity, och de föreskriver hur de kan kallas. Det är synligheten som bestämmer anropen av funktionerna; externt av användare, av andra härledda kontrakt, endast internt eller endast externt. Låt oss titta på hur felaktig användning av synlighetsspecifikationer kan orsaka enorm sårbarhet i smarta kontrakt.
Sårbarheten
Som standard är funktionens synlighet [offentlig], varför de externa användarna kan ringa funktionerna utan någon specifik synlighet. Felet uppstår när utvecklare glömmer att specificera synlighet på funktioner som ska vara privata (eller som kan anropas inom själva kontraktet). Till exempel;
kontrakt HashForEther {
funktionen Hämta vinster () {
// Vinnare om de sista åtta hexaderna i adressen är 8
kräver (uint32 (msg.sender) == 0);
_sendWinnings ();
}
funktion _sendWinnings () {
msg.sender.transfer (this.balance);
}
}
Ovanstående kontrakt är ett enkelt adressgissande bountyspel. I detta kan vi se att synligheten för funktionerna inte är specificerad, särskilt funktionen [_sendWinnings] är [offentlig] (som standard), därför kan detta anropas via vilken adress som helst för att stjäla bounty.
QuillAudits tillvägagångssätt
Vårt inbyggda team består av erfarna utvecklare som alltid följer de bästa revisionsmetoderna, här ska synligheten för funktionerna anges specifikt, även om de ska hållas offentliga, bör det nämnas.
4. Säkerställa användningen av konstruktörer
Generellt kallas konstruktörer specialfunktioner som används för att utföra kritiska och privilegierade uppgifter under initialiseringen av kontrakten. Innan Solidity [v0.4.22] hade konstruktörer samma namn som användes i kontraktet som innehöll dem. Tänk nu på ett fall där kontraktsnamnet ändras under utvecklingsfasen men konstruktörens namn förblir detsamma, detta kryphål kan också ge angripare en enkel inträde till ditt smarta kontrakt.
Sårbarheten
Det kan leda till allvarliga konsekvenser om kontraktsnamnet ändras men konstruktörens namn är oförändrat. Till exempel:
kontrakt OwnerWallet {
adressera allmän ägare;
// konstruktör
funktionsägareWallet (adress _ägare) offentlig {
ägare = _ägare;
}
// Retirera. Samla eter.
funktion () betalas {}
funktion återkalla () offentlig {
kräver (msg.sender == ägare);
msg.sender.transfer (this.balance);
}
}
I ovanstående kontrakt kan vi se att endast ägaren kan dra tillbaka eter genom att ringa funktionen [dra tillbaka]. Här uppstår sårbarheten när konstruktören heter annorlunda än kontraktet (första bokstaven är annorlunda!). Således kan exploatören ringa [ownerWallet] -funktionen och auktorisera sig som ägare och sedan dra tillbaka all etern i kontraktet genom att ringa [dra tillbaka].
QuillAudits tillvägagångssätt
Vi följer version [0.4.22] av Solidity-kompilatorn. Denna version har infört ett nyckelord; [konstruktör] som kräver att namnet på funktionen matchar kontraktsnamnet.
5. Tx.Origin-autentisering
Här är [Tx.Origin] Soliditets globala variabel, den innehåller adressen till kontot som ursprungligen utförde samtalet eller transaktionen. Den här variabeln kan inte användas för autentisering, eftersom detta gör kontrakten sårbar för phishing-attacker.
Sårbarheten
Kontrakt som auktoriserar användare via variabeln [tx.origin] utsätts för externa attacker som leder till att användare utför autentiserade åtgärder på det felaktiga kontraktet. Tänk på exemplet nedan:
kontrakt Phishable {
adressera allmän ägare;
konstruktör (adress _ägare) {
ägare = _ägare;
}
funktion () extern betalning {} // samla in eter
funktion pullAll (adress _mottagare) offentlig {
kräver (tx.origin == ägare);
_recipient.transfer (denna. balans);
}
}
Här på rad [11] godkänner avtalet funktionen [återkallaAll] med hjälp av [tx.origin].
QuillAudits tillvägagångssätt
Vi undviker i allmänhet att använda [tx.origin] för auktorisering i smarta kontrakt. Även om användningen av [tx.origin] inte är strängt förbjuden har det vissa specifika användningsfall. Vi kan använda [tx.origin] för att neka externa kontrakt från att anropa det nuvarande kontraktet, det kan köras med [kräver] i formuläret [kräver (tx.origin == msg.sender)]. Det görs för att undvika anrop av mellanliggande kontrakt för att ringa det nuvarande kontraktet, vilket begränsar kontraktet till vanliga kodlösa adresser.
Final Wrap-Up
Vi har omfattande täckt de fem vanliga fallgroparna i fasthetsspråket. När vi utvecklar smarta kontrakt får vi inte glömma att de är oföränderliga genom design, vilket innebär att när vi skapar dem finns det inget sätt att korrigera källkoden.
Detta utgör en stor utmaning för utvecklare att dra nytta av tillgängliga säkerhetstestnings- och granskningsverktyg före distribution.
Att upptäcka potentiella skadliga hot mot smarta kontrakt och de risker som vi nämnde ovan utförs på ett mycket unikt och robust sätt av vårt interna team av revisionsexperter. Vi på QuillAudits gör vårt bästa för säkerhetsforskning för att hålla ditt kontrakt uppdaterat med all mjukvarusäkerhetspraxis för att hålla ditt kontrakt säkert.
Nå ut till QuillHash
Med en branschnärvaro av år, QuillHash har levererat företagslösningar över hela världen. QuillHash med ett team av experter är ett ledande blockchain-utvecklingsföretag som tillhandahåller olika branschlösningar inklusive DeFi-företag. Om du behöver hjälp med smarta kontraktsgranskningen, kontakta gärna våra experter här!
Följ QuillHash för mer uppdateringar
Källa: https://blog.quillhash.com/2021/06/04/top-5-common-errors-in-solidity-programming-language/
- 11
- Konto
- Fördel
- Alla
- revision
- Autentisering
- tillstånd
- BÄST
- blockchain
- Bug
- fel
- Ring
- fall
- Orsak
- utmanar
- koda
- Gemensam
- företag
- kontrakt
- kontrakt
- Aktuella
- <b>PostNord</b>
- Defi
- Designa
- Utvecklare
- utvecklare
- Utveckling
- Företag
- Eter
- ethereum
- händelse
- experter
- finansiella
- Förnamn
- följer
- formen
- Fri
- fungera
- framtida
- lek
- GAS
- Välgörenhet
- stor
- hacka
- här.
- Hur ser din drömresa ut
- HTTPS
- stor
- Inklusive
- industrin
- IT
- språk
- leda
- ledande
- linje
- Lista
- Match
- Övriga
- ägaren
- Lappa
- Mönster
- Nätfiske
- phishingattacker
- ordinera
- presentera
- privat
- Programmering
- allmän
- dra
- forskning
- respons
- REST
- säker
- säkerhet
- Tjänster
- in
- Enkelt
- Small
- smarta
- smart kontrakt
- Smarta kontrakt
- So
- Mjukvara
- fasthet
- Lösningar
- Ange
- framgång
- Testning
- källan
- hot
- tid
- topp
- topp 5
- transaktion
- Transaktioner
- us
- användare
- värde
- Valv
- synlighet
- sårbarheter
- sårbarhet
- Sårbara
- vecka
- VEM
- inom
- år