Aanbevelingen voor slimme contractbeveiliging van Ethereum

blog 1NieuwsOntwikkelaarsEnterpriseBlockchain ExplainedEvenementen en conferentiesPersNieuwsbrieven

Abonneer op onze nieuwsbrief.

E-mailadres

Wij respecteren uw privacy

HomeBlogBlockchain-ontwikkeling

Aanbevelingen voor slimme contractbeveiliging van Ethereum

Van het afhandelen van externe oproepen tot toezeggingsregelingen, hier zijn 10+ slimme contractbeveiligingspatronen die u kunt volgen wanneer u aan het bouwen bent op Ethereum. By ConsenSysJuli 10, 2020Geplaatst op 10 juli 2020

Aanbevelingen voor slimme contractbeveiliging van Ethereum

Zoals we hebben besproken in de Smart Contract Security Mindset, houdt een waakzame Ethereum-ontwikkelaar altijd vijf principes voorop:

  • Bereid je voor op mislukking
  • Zorgvuldig uitrollen
  • Houd contracten simpel
  • Blijf op de hoogte
  • Houd rekening met de eigenaardigheden van de EVM

In dit bericht duiken we in de eigenaardigheden van de EVM en lopen we door een lijst met patronen die u moet volgen bij het ontwikkelen van een slim contractsysteem op Ethereum. Dit stuk is voornamelijk bedoeld voor gevorderde Ethereum-ontwikkelaars. Als je je nog in de vroege stadia van verkenning bevindt, bekijk dan het on-demand blockchain-ontwikkelaarsprogramma van ConsenSys Academy. 

Oké, laten we erin duiken.

Externe oproepen

Wees voorzichtig bij het maken van externe oproepen

Oproepen naar niet-vertrouwde slimme contracten kunnen verschillende onverwachte risico’s of fouten met zich meebrengen. Externe oproepen kunnen schadelijke code uitvoeren in dat contract of elk ander contract waarvan het afhankelijk is. Behandel daarom elk extern gesprek als een mogelijk veiligheidsrisico. Als het niet mogelijk of niet wenselijk is om externe oproepen te verwijderen, gebruik dan de aanbevelingen in de rest van deze sectie om het gevaar te minimaliseren.

Markeer niet-vertrouwde contracten

Geef bij interactie met externe contracten een naam aan uw variabelen, methoden en contractinterfaces op een manier die duidelijk maakt dat interactie met hen mogelijk onveilig is. Dit geldt voor uw eigen functies die externe contracten oproepen.

// slechte Bank.withdraw (100); // Onduidelijk of vertrouwde of niet-vertrouwde functie makeWithdrawal (uint bedrag) {// Is niet duidelijk dat deze functie potentieel onveilig is Bank.withdraw (bedrag); } // goed UntrustedBank.withdraw (100); // niet-vertrouwde externe oproep TrustedBank.withdraw (100); // extern maar vertrouwd bankcontract onderhouden door XYZ Corp-functie makeUntrustedWithdrawal (uint-bedrag) {UntrustedBank.withdraw (bedrag); } Codetaal: PHP (php)

Vermijd statuswijzigingen na externe oproepen

Of u nu onbewerkte aanroepen (in de vorm someAddress.call ()) of contractaanroepen (in de vorm ExternalContract.someMethod ()) gebruikt, neem aan dat schadelijke code kan worden uitgevoerd. Zelfs als ExternalContract niet kwaadaardig is, kan kwaadaardige code worden uitgevoerd door alle contracten die het aanroept.

Een bijzonder gevaar is dat kwaadaardige code de controlestroom kan kapen, wat kan leiden tot kwetsbaarheden als gevolg van herintreding. (Zien Herintreding voor een uitgebreidere bespreking van dit probleem).

Als u belt naar een niet-vertrouwd extern contract, vermijd dan statuswijzigingen na het gesprek. Dit patroon wordt ook wel het checks-effects-interactions patroon.

Zien SWC-107

Gebruik geen transfer () of send ().

.transfer () en.send () stuur precies 2.300 gas naar de ontvanger. Het doel van dit hard gecodeerde gasgeld was om te voorkomen kwetsbaarheden voor herintreding, maar dit is alleen logisch in de veronderstelling dat de gaskosten constant zijn. EIP 1884, dat deel uitmaakte van de hard fork van Istanbul, verhoogde de gaskosten van de SLOAD-operatie. Dit zorgde ervoor dat de terugvalfunctie van een contract meer dan 2300 gas kostte. We raden aan om te stoppen met use.transfer () en.send () en in plaats daarvan use.call ().

// slecht contract Kwetsbaar {functie intrekken (uint256 bedrag) extern {// Dit stuurt 2300 gas door, wat misschien niet genoeg is als de ontvanger // een contract is en de gaskosten veranderen. msg.sender.transfer (bedrag); }} // goed contract Vaste {functie intrekken (uint256 bedrag) extern {// Dit stuurt al het beschikbare gas door. Controleer zeker de retourwaarde! (bool success,) = msg.sender.call.value (bedrag) (""​vereisen (succes, "Overdracht mislukt."​}} Codetaal: JavaScript (javascript)

Merk op dat .call () niets doet om herintredingsaanvallen te verminderen, dus moeten andere voorzorgsmaatregelen worden genomen. Gebruik het checks-effects-interactions patroon.

Verwerk fouten in externe oproepen

Solidity biedt aanroepmethoden op laag niveau die werken op onbewerkte adressen: address.call (), address.callcode (), address.delegatecall () en address.send (). Deze methoden op laag niveau genereren nooit een uitzondering, maar zullen false retourneren als de aanroep een uitzondering tegenkomt. Aan de andere kant zullen contractoproepen (bijvoorbeeld ExternalContract.doSomething ()) automatisch een worp verspreiden (bijvoorbeeld ExternalContract.doSomething () zal ook gooien als doSomething () gooit).

Als u ervoor kiest om de aanroepmethoden op laag niveau te gebruiken, zorg er dan voor dat u de mogelijkheid aanpakt dat de aanroep mislukt door de retourwaarde te controleren.

// slecht someAddress.send (55); someAddress.call.value (55) (""​// dit is dubbel gevaarlijk, omdat het al het resterende gas doorstuurt en het resultaat someAddress.call.value (100) (bytes4 (sha3 ("storting()"​// als storting een uitzondering genereert, retourneert de raw call () alleen false en wordt de transactie NIET teruggedraaid // good (bool success,) = someAddress.call.value (55) (""​if (! success) {// afhandelen foutcode} ExternalContract (someAddress) .deposit.value (100) (); Codetaal: JavaScript (javascript)

Zien SWC-104

Geef de voorkeur aan push over push voor externe oproepen

Externe oproepen kunnen per ongeluk of opzettelijk mislukken. Om de schade veroorzaakt door dergelijke storingen te minimaliseren, is het vaak beter om elke externe oproep te isoleren in zijn eigen transactie die kan worden geïnitieerd door de ontvanger van de oproep. Dit is vooral relevant voor betalingen, waar het beter is om gebruikers geld te laten opnemen in plaats van automatisch geld naar hen te sturen. (Dit verkleint ook de kans op problemen met de gaslimiet.) Vermijd het combineren van meerdere etheroverdrachten in één transactie.

// slechte contractveiling {adres hoogste bieder; uint hoogsteBod; functie bid () te betalen {vereisen (msg.value >= hoogste bod); if (hoogste bieder! = adres (0)) {(bool succes,) = hoogste bieder.call.value (hoogste bieding) (""​vereisen (succes); // als deze oproep consequent mislukt, kan niemand anders bieden} hoogsteBidder = msg.sender; hoogsteBod = msg.waarde; }} // goed contract veiling {adres hoogste bieder; uint hoogsteBod; mapping (adres => uint) restituties; functie bid () betaalbaar extern {vereisen (msg.value >= hoogste bod); if (hoogste bieder! = adres (0)) {terugbetalingen [hoogste bieder] + = hoogste bieding; // registreer de terugbetaling die deze gebruiker kan claimen} hoogsteBidder = msg.sender; hoogsteBod = msg.waarde; } functie terugtrekRefund () externe {uint terugbetaling = terugbetalingen [msg.sender]; terugbetalingen [msg.sender] = 0; (bool success,) = msg.sender.call.value (terugbetaling) (""​vereisen (succes); }} Codetaal: JavaScript (javascript)

Zien SWC-128

Delegeer oproepen niet naar niet-vertrouwde code

De delegatecall-functie roept functies uit andere contracten op alsof ze bij het beller-contract horen. De opgeroepene kan dus de staat van het aanroepadres wijzigen. Dit kan onzeker zijn. Een voorbeeld hieronder laat zien hoe het gebruik van delegatecall kan leiden tot de vernietiging van het contract en verlies van het evenwicht.

contract Destructor {functie doWork () externe {selfdestruct (0); }} contractmedewerker {functie doWork (adres _internalWorker) openbaar {// onveilig _internalWorker.delegatecall (bytes4 (keccak256 ("werken()"​}} Codetaal: JavaScript (javascript)

Als Worker.doWork () wordt aangeroepen met het adres van het ingezette Destructor-contract als argument, vernietigt het Worker-contract zichzelf. Delegeer de uitvoering alleen aan vertrouwde contracten, en nooit naar een door de gebruiker opgegeven adres.

Waarschuwing

Ga er niet vanuit dat contracten worden gemaakt met een saldo van nul. Een aanvaller kan ether naar het adres van een contract sturen voordat het wordt aangemaakt. Contracten mogen er niet van uitgaan dat de oorspronkelijke staat een saldo van nul bevat. Zien kwestie 61 voor meer details.

Zien SWC-112

Onthoud dat ether met geweld naar een account kan worden gestuurd

Pas op voor het coderen van een invariant die de balans van een contract strikt controleert.

Een aanvaller kan ether met geweld naar elk account sturen. Dit kan niet worden voorkomen (zelfs niet met een fallback-functie die een revert () doet).

De aanvaller kan dit doen door een contract aan te maken, dit met 1 wei te financieren en zelfvernietiging (victimAddress) aan te roepen. Er wordt geen code aangeroepen in victimAddress, dus het kan niet worden voorkomen. Dit geldt ook voor blokbeloningen die naar het adres van de mijnwerker worden gestuurd, wat elk willekeurig adres kan zijn.

Omdat contractadressen vooraf kunnen worden berekend, kan ether naar een adres worden gestuurd voordat het contract wordt geïmplementeerd.

Zien SWC-132

Onthoud dat on-chain-gegevens openbaar zijn

Veel aanvragen vereisen dat de ingediende gegevens tot een bepaald moment privé blijven om te kunnen werken. Spellen (bijv. Steen-papier-schaar aan de ketting) en veilingmechanismen (bijv. Verzegeld bod Vickrey veilingen) zijn twee belangrijke categorieën voorbeelden. Als u een toepassing bouwt waarbij privacy een probleem is, zorg er dan voor dat u niet van gebruikers verlangt dat zij informatie te vroeg publiceren. De beste strategie is om te gebruiken toezeggingsregelingen met afzonderlijke fasen: eerst commit met de hash van de waarden en in een latere fase de waarden onthullen.

Voorbeelden:

  • In steenpapier-schaar moeten beide spelers eerst een hash van hun voorgenomen zet indienen, en vervolgens moeten beide spelers hun zet indienen; als de ingediende zet niet overeenkomt met de hash, gooi deze dan weg.
  • In een veiling, vereisen spelers dat ze een hash van hun biedwaarde indienen in een eerste fase (samen met een storting die hoger is dan hun biedwaarde), en vervolgens hun biedingswaarde indienen in de tweede fase.
  • Bij het ontwikkelen van een applicatie die afhankelijk is van een generator voor willekeurige getallen, moet de volgorde altijd zijn (1) spelers die zetten indienen, (2) gegenereerde willekeurige getallen, (3) spelers uitbetaald. Veel mensen doen actief onderzoek naar het genereren van willekeurige getallen; De huidige best-in-class oplossingen omvatten Bitcoin block headers (geverifieerd door http://btcrelay.org), hash-commit-onthullingsschema’s (dwz een partij genereert een nummer, publiceert zijn hash om zich aan de waarde te “committeren” en onthult vervolgens de waarde later) en RANDAO. Omdat Ethereum een ​​deterministisch protocol is, kunt u geen enkele variabele binnen het protocol gebruiken als een onvoorspelbaar willekeurig getal. Houd er ook rekening mee dat miners tot op zekere hoogte controle hebben over de waarde block.blockhash ().

Pas op voor de mogelijkheid dat sommige deelnemers “offline vallen” en niet terugkeren

Maak restitutie- of claimprocessen niet afhankelijk van het feit dat een specifieke partij een bepaalde actie uitvoert zonder een andere manier om het geld eruit te krijgen. In een spel met steen-papier-schaar is bijvoorbeeld een veelgemaakte fout om pas uit te betalen als beide spelers hun zetten hebben ingediend; een kwaadwillende speler kan de ander echter “verdrietig” maken door simpelweg nooit zijn zet in te dienen – in feite, als een speler de geopenbaarde zet van de andere speler ziet en vaststelt dat hij verloren heeft, heeft hij helemaal geen reden om zijn eigen zet in te dienen. Dit probleem kan zich ook voordoen in de context van de afwikkeling van staatskanalen. Wanneer dergelijke situaties een probleem zijn, (1) een manier bieden om niet-deelnemende deelnemers te omzeilen, misschien door middel van een tijdslimiet, en (2) overwegen om deelnemers een extra economische prikkel te geven om informatie te verstrekken in alle situaties waarin ze zich bevinden. verondersteld dat te doen.

Pas op voor het negeren van het meest negatief ondertekende gehele getal

Solidity biedt verschillende typen om met ondertekende gehele getallen te werken. Zoals in de meeste programmeertalen, kan in Solidity een geheel getal met teken met N bits waarden vertegenwoordigen van -2 ^ (N-1) tot 2 ^ (N-1) -1. Dit betekent dat er geen positief equivalent is voor de MIN_INT. Ontkenning wordt geïmplementeerd als het vinden van het twee-complement van een getal, dus de ontkenning van het meest negatieve getal zal resulteren in hetzelfde aantal. Dit geldt voor alle typen gehele getallen met teken in Solidity (int8, int16, …, int256).

contract Negation {function negate8 (int8 _i) public pure returns (int8) {return -_i; } functie negate16 (int16 _i) openbare pure returns (int16) {return -_i; } int8 public a = negate8 (-128); // -128 int16 public b = negate16 (-128); // 128 int16 public c = negate16 (-32768); // -32768} Codetaal: PHP (php)

Een manier om hiermee om te gaan, is door de waarde van een variabele vóór negatie te controleren en te gooien als deze gelijk is aan de MIN_INT. Een andere optie is om ervoor te zorgen dat het meest negatieve getal nooit wordt behaald door een type met een hogere capaciteit te gebruiken (bijv. Int32 in plaats van int16).

Een soortgelijk probleem met int-typen doet zich voor wanneer MIN_INT wordt vermenigvuldigd of gedeeld door -1.

Is uw blockchain-code veilig?? 

We hopen dat deze aanbevelingen nuttig zijn geweest. Als u en uw team zich voorbereiden op de lancering of zelfs aan het begin van de ontwikkelingscyclus en uw slimme contracten moeten worden gecontroleerd, neem dan gerust contact op met ons team van beveiligingsingenieurs bij ConsenSys Diligence. We zijn er om u te helpen bij het lanceren en onderhouden van uw Ethereum-applicaties met 100% vertrouwen. 

Boek een Security Spot Check

Boek een 1-daagse review met ons team van blockchain-beveiligingsexperts. Boek vandaag nog BeveiligingSlimme contractenNieuwsbrief Schrijf u in op onze nieuwsbrief voor het laatste Ethereum-nieuws, bedrijfsoplossingen, bronnen voor ontwikkelaars en meer.Hoe u een succesvol blockchain-product bouwtWebinar

Hoe u een succesvol blockchain-product bouwt

Hoe u een Ethereum-knooppunt instelt en uitvoertWebinar

Hoe u een Ethereum-knooppunt instelt en uitvoert

Hoe u uw eigen Ethereum-API kunt bouwenWebinar

Hoe u uw eigen Ethereum-API kunt bouwen

Hoe u een sociaal token maaktWebinar

Hoe u een sociaal token maakt

Beveiligingshulpmiddelen gebruiken bij slimme contractontwikkelingWebinar

Beveiligingshulpmiddelen gebruiken bij slimme contractontwikkeling

De toekomst van digitale activa en defiWebinar

De toekomst van financiën: digitale activa en deFi

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