Vanliga sårbarheter i smarta kontrakt
Granska vanliga säkerhetsbrister i smarta kontrakt, till exempel reentrancy, heltalsöverflöden och heltalsunderflöden samt problem med åtkomstkontroll.
Vanliga sårbarheter i smarta kontrakt är en gratis lektion i Grunderna i Web3- och DApp-utveckling på CoddyKit. Detta är lektion 1 av 3. Du kan läsa vilka 3 lektioner som helst i den här lärvägen kostnadsfritt i sin helhet – därefter låser CoddyKit PRO upp alla lektioner, plus praktisk övning med en inbyggd kodredigerare och en AI-lärare dygnet runt. Den ingår i lärvägen för Grunderna i Web3- och DApp-utveckling, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i Grunderna i Web3- och DApp-utveckling innehåller totalt 3 lektioner.
Varför säkerhet är viktigt
Smarta kontrakt hanterar värdefulla tillgångar och utför oåterkalleliga åtgärder på blockkedjan. En enda sårbarhet kan leda till betydande ekonomiska förluster eller obehörig manipulation av kontraktet.
Till skillnad från traditionell programvara är distribuerade smarta kontrakt ofta oföränderliga. Det innebär att det kan vara mycket svårt att åtgärda buggar eller sårbarheter när ett kontrakt väl är aktivt. Ibland krävs komplexa uppgraderingsmekanismer eller till och med att kontraktet distribueras på nytt.
Reentrancy förklarat
Reentrancy är en kritisk sårbarhet där ett externt anrop från ditt kontrakt till ett annat kontrakt eller en extern adress kan ”återinträda” i det anropande kontraktet innan det ursprungliga funktionsanropet har slutförts.
Detta gör det möjligt för en angripare att upprepade gånger köra vissa delar av en funktion, vilket ofta leder till obehöriga uttag av pengar eller manipulation av tillståndet och tömmer kontraktets saldo.
Sårbart exempel på reentrancy
I det här exemplet skickar funktionen withdraw först Ether (ett externt anrop) och uppdaterar sedan användarens saldo. En angripare skulle kunna återanropa withdraw flera gånger innan saldot sätts till noll.
pragma solidity ^0.8.0;
contract VulnerableWithdraw {
mapping(address => uint) public balances;
constructor() payable {
balances[msg.sender] = msg.value;
}
function withdraw() public {
uint amount = balances[msg.sender];
require(amount > 0, "No funds to withdraw");
// Vulnerable: External call BEFORE state update
(bool success, ) = msg.sender.call{value: amount}("");
require(success, "Transfer failed");
balances[msg.sender] = 0; // State updated AFTER call
}
function deposit() public payable {
balances[msg.sender] += msg.value;
}
function getBalance() public view returns (uint) {
return address(this).balance;
}
}Förhindra reentrancy
Det mest effektiva försvaret mot reentrancy är mönstret Checks-Effects-Interactions. Mönstret anger i vilken ordning åtgärder ska utföras i dina funktioner:
- Checks: Verifiera alla villkor (t.ex.
require-satser). - Effects: Genomför alla nödvändiga ändringar av tillståndet (t.ex. uppdatera saldon och ändra variabler).
- Interactions: Utför alla externa anrop (t.ex. skicka Ether eller anropa ett annat kontrakt).
Uppdatera alltid kontraktets tillstånd *innan* du skickar Ether eller anropar externa kontrakt.
Säker uttagsfunktion
Här är den korrigerade funktionen withdraw. Lägg märke till hur användarens saldo uppdateras (en ”effect”) *innan* Ether skickas (en ”interaction”).
pragma solidity ^0.8.0;
contract SecureWithdraw {
mapping(address => uint) public balances;
constructor() payable {
balances[msg.sender] = msg.value;
}
function withdraw() public {
uint amount = balances[msg.sender];
require(amount > 0, "No funds to withdraw");
balances[msg.sender] = 0; // Effect: State updated BEFORE call
(bool success, ) = msg.sender.call{value: amount}(""); // Interaction
require(success, "Transfer failed");
}
function deposit() public payable {
balances[msg.sender] += msg.value;
}
function getBalance() public view returns (uint) {
return address(this).balance;
}
}heltalsöverflöde och underflow
Heltalstyper i Solidity (som uint eller int) har en fast storlek. Ett overflow inträffar när en aritmetisk operation ger ett värde som är större än det maximala värdet som en heltalstyp kan innehålla. Då ”slår värdet runt” till sitt minimivärde (t.ex. blir 255 + 1 på en uint8 lika med 0).
Ett underflow inträffar när en operation ger ett värde som är mindre än minimivärdet (vanligtvis 0 för uint). Då slår värdet runt till sitt maximivärde (t.ex. blir 0 - 1 på en uint8 lika med 255).
Sårbar heltalslogik
Före Solidity 0.8.0 kontrollerades dessa runtom-beteenden inte automatiskt. Det här exemplet, som använder en äldre Solidity-version, visar hur en angripare kunde utnyttja ett underflow för att få ett mycket stort saldo.
pragma solidity ^0.7.0; // Using 0.7.x to demonstrate vulnerability
contract VulnerableCounter {
uint public count = 0;
// If count is 0 and _amount is 1, count becomes type(uint).max
function decrement(uint _amount) public {
count -= _amount; // Vulnerable to underflow
}
// If count + _amount exceeds type(uint).max, count wraps around to a small number
function increment(uint _amount) public {
count += _amount; // Vulnerable to overflow
}
}Begränsa overflow och underflow
Sedan Solidity 0.8.0 återställs (misslyckas) aritmetiska operationer automatiskt vid overflow eller underflow. Detta ger ett robust skydd mot problemen som standard och gör dina kontrakt betydligt säkrare.
För kontrakt som skrevs i äldre Solidity-versioner (före 0.8.0) var det vanligt att använda bibliotek som OpenZeppelins SafeMath. SafeMath tillhandahöll funktioner (add, sub, mul, div) som utförde kontrollerad aritmetik och återställde körningen om ett overflow eller underflow skulle inträffa.
Problem med åtkomstkontroll
Åtkomstkontroll säkerställer att endast behöriga användare eller roller kan utföra specifika, känsliga åtgärder i ett smart kontrakt. Felaktig åtkomstkontroll är en mycket vanlig källa till sårbarheter.
Vanliga misstag är bland annat:
- Att auktoriseringskontroller saknas för kritiska funktioner (t.ex. administrativa funktioner).
- Att använda
msg.senderdirekt utan att verifiera ägarskap eller roll. - Svaga eller lättgissade auktoriseringsmekanismer.
Sårbar åtkomstkontroll
I det här exemplet är funktionen setCriticalValue avsedd att endast kunna användas av kontraktets ägare, men den saknar en kontroll som upprätthåller detta. Vilken användare som helst skulle kunna anropa funktionen och ändra det kritiska värdet.
Modifieraren onlyOwner visar rätt sätt att begränsa åtkomsten.
pragma solidity ^0.8.0;
contract VulnerableAccess {
address public owner;
uint public criticalValue;
constructor() {
owner = msg.sender;
criticalValue = 100;
}
// Vulnerable: This function should be owner-only, but it's public!
function setCriticalValue(uint _newValue) public {
criticalValue = _newValue; // Anyone can call this!
}
// Correct way to restrict access using a modifier
function setCriticalValueSecure(uint _newValue) public onlyOwner {
criticalValue = _newValue;
}
modifier onlyOwner() {
require(msg.sender == owner, "Not owner");
_;
}
}Kontrollera sårbarheter
Vilket av följande mönster är utformat för att förhindra reentrancy-attacker genom att säkerställa att tillståndsändringar sker före externa anrop?
Sammanfattning: Säkra smarta kontrakt
I dag har vi gått igenom några av de vanligaste och mest kritiska sårbarheterna i smarta kontrakt:
- Reentrancy: Förhindras genom att följa mönstret Checks-Effects-Interactions.
- Integer Overflow/Underflow: Begränsas genom att använda Solidity 0.8.0+ (automatiska kontroller) eller SafeMath för äldre versioner.
- Problem med åtkomstkontroll: Säkerställs genom att införa korrekta auktoriseringskontroller med hjälp av modifierare som
onlyOwner.
Prioritera alltid säkerheten när du utvecklar smarta kontrakt. Att granska koden noggrant och följa bästa praxis är viktiga steg för att skydda tillgångar och säkerställa att dina decentraliserade applikationer är tillförlitliga.
Lär dig Grunderna i Web3- och DApp-utveckling med en AI-lärare – gratis
Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.
- Kurser
- 29
- Lektioner
- 105
Vanliga frågor
Är lektionen ”Vanliga sårbarheter i smarta kontrakt” gratis?
Ja – du kan läsa vilka 3 lektioner som helst i lärvägen Grunderna i Web3- och DApp-utveckling, inklusive ”Vanliga sårbarheter i smarta kontrakt”, kostnadsfritt i sin helhet här på webben. Därefter låser CoddyKit PRO upp alla lektioner, plus interaktiv övning med en inbyggd kodredigerare och en AI-lärare dygnet runt. Kursen i Grunderna i Web3- och DApp-utveckling innehåller totalt 3 lektioner.
Vad lär jag mig i ”Vanliga sårbarheter i smarta kontrakt”?
Granska vanliga säkerhetsbrister i smarta kontrakt, till exempel reentrancy, heltalsöverflöden och heltalsunderflöden samt problem med åtkomstkontroll. Ni övar på Grunderna i Web3- och DApp-utveckling med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.
Behöver jag någon erfarenhet för att börja lära mig Grunderna i Web3- och DApp-utveckling?
Du behöver inga förkunskaper. Utbildningen i Grunderna i Web3- och DApp-utveckling på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 1 av 3.
Hur lång tid tar lektionen ”Vanliga sårbarheter i smarta kontrakt”?
De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.
Kan jag skriva och köra kod i den här Grunderna i Web3- och DApp-utveckling-lektionen?
Ja. Varje Grunderna i Web3- och DApp-utveckling-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.
Alla lektioner i den här kursen
- Vanliga sårbarheter i smarta kontrakt
- Säkerhetsverktyg och granskningar
- Tekniker för gasoptimering