Vi har netop set, hvordan et lille smuthul fører til et økonomisk tab (af varierende størrelse), på samme måde som smarte kontrakter udviklet over Solidity er tilbøjelige til forskellige kendte og ukendte angreb. Udbytterne drager fordel af fejl og smuthuller til at kigge ind i smarte kontrakter og manipulere dem til at udføre angreb. Her præsenterer vi en omfattende liste over de 5 mest almindelige fejl i programmeringssproget Solidity.
Hos QuillAudits følger vi den adaptive metodologi for at få essensen af hvert hack og implementere dets læring på fremtidige smarte kontrakter for at undgå enhver potentiel trussel.
Fejl i solidity programmeringssprog
1. Ikke markeret eksternt opkald
Vi trækker dette problem i første omgang, fordi det er en af de mest almindeligt observerede Soliditets faldgruber. Generelt, at sende ether til enhver ekstern konto udføres gennem overførsel() fungere. Ud over dette er de to mest brugte funktioner til at foretage et eksternt opkald; opkald()og send (), her hovedsageligt opkald() funktion er flittigt brugt til at udføre alsidige eksterne opkald af udviklerne.
Selvom opkald() , send () funktioner returnerer en boolesk værdi, der angiver, om opkaldet var en succes eller ej. Således i dette tilfælde, hvis nogen af funktionerne opkald() or send () undlader at udføre opgaven, vil de vende tilbage med en falsk. Derfor, hvis udvikleren ikke krydstjekker returværdien, ville det blive en faldgrube.
Sårbarheden
Overvej eksemplet nedenfor:
kontrakt Lotto{
boolpublic payedOut =falsk;
adresse offentlig vinder;
uintpublic winAmount;
// … ekstra funktionalitet her
function sendToWinner()public{
require(!payedOut);
vinder.send(vindBeløb);
payedOut =sand;
}
function withdrawLeftOver()public{
kræve(udbetalt);
msg.sender.send(this.balance);
}
}
I den Lotto-lignende kontrakt ovenfor kan vi observere, at en vinder modtager winBeløb af ether efterlader en lille rest, der skal trækkes tilbage fra enhver ekstern agent.
Her findes faldgruben for kontrakten på linje [11], hvor en send bruges uden krydsvalidering af svaret. I ovenstående eksempel, a vinder hvis transaktion mislykkes (enten på grund af gasmangel, eller hvis det er en kontrakt, der med vilje tillader reservefunktionen), autoriserer udbetalt skal indstilles til sand uanset om transaktionen med ether var en succes eller ej. I dette tilfælde kan enhver udnytter trække tilbage vinderens gevinster via tilbagetrækkeLeftOver funktion.
QuillAudits tilgang
Vores interne team af udviklere tackler denne fejl ved at bruge [overførsel] funktion i stedet for [sende] funktion, da [overførsel] vil vende tilbage, hvis ekstern transaktion vender tilbage. Og hvis du bruger [send], krydstjek altid returværdien.
En af de robuste tilgange, vi følger, er at bruge et [tilbagetrækningsmønster]. Her isolerer vi logisk den eksterne sendefunktionalitet fra resten af kodebasen og lægger belastningen af potentielt mislykkede transaktioner på slutbrugeren, da det er ham, der kalder tilbagetrækningsfunktionen.
2. Re-Entrance
Ethereums smarte kontrakter kalder og bruger koder fra andre eksterne kontrakter, og for at udføre dette er kontrakterne forpligtet til at sende eksterne opkald. Disse eksterne opkald er sårbare og tilbøjelige til angreb, et sådant angreb fandt sted for nylig i tilfælde af DAO-hack.
Sårbarheden
Angribere udfører sådanne angreb, når en kontrakt sender ether til en ukendt adresse. I dette tilfælde kan angriberen oprette en kontrakt på en ekstern adresse, der besidder skadelig kode i fallback-funktionen, og denne skadelige kode vil blive påkaldt, når kontrakten sender ether til denne adresse.
Faktum: Udtrykket 'Reentrancy' er opstået fra det faktum, at når en ekstern ondsindet kontrakt kalder en funktion over den sårbare kontrakt, og derefter kodeudførelsesstien 'genindtræder' den.
Overvej eksemplet nedenfor, det er en Ethereum-boks, der tillader indskydere kun at hæve 1 ether om ugen.
kontrakt EtherStore {
uint256 offentlig tilbagetrækning Limit = 1 ether;
mapping (adresse => uint256) public lastWithdrawTime;
mapping(adresse => uint256) offentlige saldi;
function depositFunds() eksternt betales {
saldi[msg.sender] += msg.value;
}
function withdrawFunds (uint256 _weiToWithdraw) public {
require(saldi[msg.sender] >= _weiToUdtræk);
// begrænse tilbagetrækningen
require(_weiToUdtræk <= tilbagetrækningsgrænse);
// begrænse den tilladte tid til at trække sig tilbage
require(nu >= sidste tilbagetrækningstid[msg.sender] + 1 uger);
require(msg.sender.call.value(_weiToWithdraw)());
saldi[msg.sender] -= _weiToUdtræk;
lastWithdrawTime[msg.sender] = nu;
}
}
I ovenstående kontrakt har vi to offentlige funktioner, [depositFunds] og [withdrawFunds]. [depositFunds] bruges til at øge afsenderens saldo, hvorimod [withdrawFunds] angiver det beløb, der skal hæves. I dette tilfælde vil det være en succes, hvis beløbet, der skal hæves, er mindre end 1 ether.
Faldgruben her ligger i linje [17], hvor overførslen af æter finder sted. Angriberen kunne oprette en ondsindet kontrakt med [EtherStores]'s kontraktadresse som den eneste konstruktørparameter. Dette ville gøre [etherStore] til en offentlig variabel, og derfor mere tilbøjelig til at blive angrebet.
QuilllAudits tilgang
Vi følger forskellige teknikker for at undgå potentielle genindtrædende sårbarheder i smarte kontrakter. Den allerførste og bedst mulige måde er brugen af den indbyggede [transfer]-funktion, når du overfører ether til en ekstern kontrakt.
For det andet er det vigtigt at sikre, at alle logiske ændringer i tilstandsvariablerne skal udføres, før ether sendes ud af kontrakten. I eksemplet [EtherStore] skal linje [18] og [19] sættes før linje [17].
En tredje teknik kan også bruges til at forhindre genindtrædende opkald; gennem indførelsen af en mutex. Det er en tilføjelse af en tilstandsvariabel, der låser kontrakten under kodeudførelse.
3. Standardsynligheder
Der er synlighedsspecifikationer for de funktioner, vi bruger i Solidity, og de foreskriver, hvordan de kan kaldes. Det er synligheden, der bestemmer funktionernes kald; eksternt af brugere, af andre afledte kontrakter, kun internt eller kun eksternt. Lad os se på, hvordan fejlagtig brug af synlighedsspecifikationer kan forårsage enorm sårbarhed i smarte kontrakter.
Sårbarheden
Funktionens synlighed er som standard [offentlig], hvorfor de eksterne brugere kan kalde funktionerne uden specifik synlighed. Fejlen opstår, når udviklere glemmer at angive synlighed på funktioner, der skal være private (eller kan kaldes i selve kontrakten). For eksempel;
kontrakt HashForEther {
function withdrawWinnings() {
// Vinder, hvis de sidste 8 hex-tegn i adressen er 0
require(uint32(msg.sender) == 0);
_sendWinnings();
}
function _sendWinnings() {
msg.sender.transfer(this.balance);
}
}
Ovenstående kontrakt er et simpelt adresse-gættende dusørspil. I dette kan vi se, at synligheden af funktionerne ikke er specificeret, især funktionen [ _sendWinnings] er [public] (som standard), derfor kan denne kaldes gennem enhver adresse for at stjæle dusøren.
QuillAudits tilgang
Vores in-house team består af garvede udviklere, som altid følger den bedste revisionspraksis, her bør synligheden af funktionerne specificeres eksplicit, selvom de skal holdes offentlige, skal det nævnes.
4. Sikring af brugen af konstruktører
Generelt kaldes konstruktører specielle funktioner, der bruges til at udføre kritiske og privilegerede opgaver, mens kontrakterne initialiseres. Før Solidity [v0.4.22] havde konstruktører det samme navn, som blev brugt af kontrakten, der indeholdt dem. Overvej nu et tilfælde, hvor kontraktnavnet ændres under udviklingsfasen, men konstruktørnavnet forbliver det samme. Dette smuthul kan også give angribere en nem adgang til din smarte kontrakt.
Sårbarheden
Det kan føre til alvorlige konsekvenser, hvis kontraktnavnet ændres, men konstruktørens navn er uændret. For eksempel:
kontrakt OwnerWallet {
adresse offentlig ejer;
// konstruktør
function ownerWallet(adresse _owner) public {
ejer = _ejer;
}
// Falde tilbage. Saml ether.
funktion () betales {}
function withdraw() public {
require(msg.sender == ejer);
msg.sender.transfer(this.balance);
}
}
I ovenstående kontrakt kan vi se, at det kun er ejeren, der kan hæve ether ved at kalde [tilbagetrækning]-funktionen. Her opstår sårbarheden, da konstruktøren er navngivet anderledes end kontrakten (første bogstav er anderledes!). Udnytteren kan således kalde [ownerWallet]-funktionen og autorisere sig selv som ejer, og derefter trække al ether i kontrakten tilbage ved at kalde [tilbagetrækning].
QuillAudits tilgang
Vi overholder version [0.4.22] af Solidity-kompileren. Denne version har introduceret et nøgleord; [konstruktør] som kræver, at navnet på funktionen matcher kontraktnavnet.
5. Tx.Origin Authentication
Her er [Tx.Origin] Soliditys globale variabel, den indeholder adressen på den konto, der oprindeligt udførte opkaldet eller transaktionen. Denne variabel kan ikke bruges til godkendelse, da det gør kontrakten sårbar over for phishing-angreb.
Sårbarheden
Kontrakter, der autoriserer brugere gennem variabelen [tx.origin] er udsat for eksterne angreb, der får brugerne til at udføre autentificerede handlinger på den fejlagtige kontrakt. Overvej nedenstående eksempel:
kontrakt Phishable {
adresse offentlig ejer;
konstruktør (adresse _ejer) {
ejer = _ejer;
}
funktion () eksternt betales {} // indsamle ether
function withdrawAll(adresse _recipient) public {
require(tx.origin == ejer);
_recipient.transfer(this.balance);
}
}
Her på linje [11] tillader kontrakten [tilbagetrækningAlle]-funktionen ved hjælp af [tx.origin].
QuillAudits tilgang
Vi undgår generelt at bruge [tx.origin] til autorisation i smarte kontrakter. Selvom brugen af [tx.origin] ikke er strengt forbudt, har det nogle specifikke brugstilfælde. Vi kan bruge [tx.origin] til at nægte eksterne kontrakter at kalde den nuværende kontrakt, den kan udføres med [require] i formen [require(tx.origin == msg.sender)]. Det gøres for at undgå indkaldelse af mellemkontrakter at kalde den nuværende kontrakt, hvilket begrænser kontrakten til almindelige kodeløse adresser.
Endelig afslutning
Vi har udførligt dækket de fem almindelige faldgruber i soliditetssproget. Mens vi udvikler smarte kontrakter, må vi ikke glemme, at de er uforanderlige af design, hvilket betyder, at når vi først har oprettet dem, er der ingen måde at patche kildekoden på.
Dette udgør en stor udfordring for udviklere til at drage fordel af tilgængelige sikkerhedstest- og revisionsværktøjer før implementering.
Opdagelse af potentielle ondsindede trusler mod de smarte kontrakter og de risici, som nogle af dem nævnte ovenfor, udføres på en meget unik og robust måde af vores interne team af revisionseksperter. Vi hos QuillAudits gør vores bedste for sikkerhedsundersøgelser for at holde din kontrakt opdateret med al softwaresikkerhedspraksis for at holde din kontrakt sikker.
Nå ud til QuillHash
Med en branche tilstedeværelse af år, QuillHash har leveret virksomhedsløsninger over hele kloden. QuillHash med et team af eksperter er et førende blockchain-udviklingsfirma, der leverer forskellige brancheløsninger, herunder DeFi-virksomhed. Hvis du har brug for hjælp til smart kontrakter revision, er du velkommen til at kontakte vores eksperter her!
Følg QuillHash for flere opdateringer
Kilde: https://blog.quillhash.com/2021/06/04/top-5-common-errors-in-solidity-programming-language/
- 11
- Konto
- Fordel
- Alle
- revision
- Godkendelse
- tilladelse
- BEDSTE
- blockchain
- Bug
- bugs
- ringe
- tilfælde
- Årsag
- udfordre
- kode
- Fælles
- selskab
- kontrakt
- kontrakter
- Nuværende
- DAO
- Defi
- Design
- Udvikler
- udviklere
- Udvikling
- Enterprise
- Ether
- ethereum
- begivenhed
- eksperter
- finansielle
- Fornavn
- følger
- formular
- Gratis
- funktion
- fremtiden
- spil
- GAS
- Global
- stor
- hack
- link.
- Hvordan
- HTTPS
- kæmpe
- Herunder
- industrien
- IT
- Sprog
- føre
- førende
- Line (linje)
- Liste
- Match
- Andet
- ejer
- patch
- Mønster
- Phishing
- phishing-angreb
- ordinere
- præsentere
- private
- Programmering
- offentlige
- trækker
- forskning
- svar
- REST
- sikker
- sikkerhed
- Tjenester
- sæt
- Simpelt
- lille
- Smart
- smart kontrakt
- Smarte kontrakter
- So
- Software
- soliditet
- Løsninger
- Tilstand
- succes
- Test
- The Source
- trusler
- tid
- top
- top 5
- transaktion
- Transaktioner
- us
- brugere
- værdi
- Vault
- synlighed
- Sårbarheder
- sårbarhed
- Sårbar
- uge
- WHO
- inden for
- år