Blog

Smart contracts: een praktische gids om belangrijke valkuilen te vermijden

[blog] Blockchain heeft heel wat in z'n mars. Wie met de technologie wil werken om smart contracts mogelijk te maken, moet echter zijn ogen openhouden voor potentiële struikelblokken.

 

Ethereum is het meest populaire blockchain-platform voor ‘smart contracts’. Dit zijn stukjes code die gedistribueerd worden uitgevoerd binnen een blockchain-netwerk. Voor iemand met een beetje programmeerachtergrond ziet een smart contract in Ethereum eruit als normale code. Toch zijn er specifieke valkuilen waarop je moet letten en waartegen zelfs kenners zich bezondigen. Twee denkfouten hieronder geven aan dat de realiteit toch wat complexer is dat ze op het eerste zicht doet vermoeden.

 

Alle parameters mee in de blockchain?

 

Eind 2016, op een seminarie over smart contracts, probeerde één van de sprekers ons te overtuigen van de eenvoud van deze technologie. Helaas maakte hij zelf een fundamentele fout. Daaruit bleek dat hij eigenlijk – net zoals het publiek – nog onvoldoende de details van zijn onderwerp beheerste.

 

Een smart contract liet een notaris toe om aan te geven dat een document verwerkt was. De code wordt – licht vereenvoudigd – weergegeven in figuur 1. De notaris registreert een document via de functie notarize(). Deze functie voegt normaliter aan de variabele ‘proofs een element toe met de unieke SHA-256-vingerafdruk van het document (32-bytes hash), en de waarde ‘true’. Op het eerste gezicht lijkt dit prima.

 

 

Het oproepen van een functie die de contracttoestand wijzigt, gebeurt hier echter via een transactie die op de blockchain terechtkomt. Om de notarize()-functie uit te voeren, creëert de notaris met zijn private sleutel een transactie. Daarin zit onder meer het adres van het smart contract, de identificatiesleutel van de functie, en – dit is essentieel hier – de parameters die aan de functie meegegeven worden.

 

Onhandelbaar

 

Hoewel enkel de vingerafdruk van het document in het smart contract terechtkomt, wordt dus het volledige document (!) in een transactie op de blockchain bewaard. Dat maakt niet enkel de blockchain al gauw onhandelbaar groot. Bovendien worden alle verwerkte documenten, die uiteraard gevoelige gegevens bevatten, voor de hele wereld toegankelijk. Eens een document in de Ethereum-blockchain terechtkomt, kan het in principe ook niet meer verwijderd of gewijzigd worden.

 

Er is meer. Wanneer een notaris code wil uitvoeren op een smart contract, dan betaalt hij daarvoor. Ethereum-miners zijn immers alleen bereid om je transactie te verwerken, als ze daarvoor een voldoende hoge vergoeding krijgen. Je betaalt méér voor transacties die meer data bevatten, en je betaalt ook méér wanneer er meer rekenkracht en/of opslag vereist is voor het uitvoeren van de code zelf. Samen zou het oproepen van deze notarize()-functie voor een document van 1MB eind december 2017 al een kleine 2000 dollar gekost hebben.

 

Al deze zaken kunnen eenvoudig verholpen worden door de vingerafdruk (hash) te berekenen op de client, en enkel dit als parameter mee te geven aan de notarize()-functie. Dat resulteert in de code in figuur 2. De ironie is dat we in het smart contract nu gewoon sleutelparen opslaan – wat evengoed kan zonder smart contract. Een erg overtuigend voorbeeld van de meerwaarde van smart contracts is dit dus helaas niet.

 

Digitale bankroof

 

In het voorjaar van 2016 werd met blockchaintechnologie een ‘decentraal risicokapitaalfonds’ opgericht, genaamd ‘The DAO’. De basis is een set van smart contracts waarop je met Ether, de cryptomunt van Ethereum, stemrecht koopt. Hoe meer geld je in het contract stort, hoe meer stemrecht je hebt. Er konden projecten ingediend worden en wanneer een project voldoende ja-stemmen haalde, kreeg het financiering.

 

Op een gegeven moment bevatte het fonds 168 miljoen dollar aan Ether; wat gelijk was aan 14% van alle op dat moment bestaande Ether. Helaas bevatte het smart contract een bug waardoor er 54 miljoen dollar weglekte naar een aanvaller. De meerderheid van de miners ging akkoord om de blockchain terug te draaien, waardoor de meest recente geschiedenis van de blockchain collectief werd geschrapt en de aanval dus, volgens de blockchain althans, nooit gebeurd was.

 

Een contract is ook een rekening

 

Waar liep het fout? Om te participeren in open publieke blockchain-netwerken zoals Bitcoin en Ethereum, registreer je eerst een externe account. Je maakt lokaal een publiek-privaat sleutelpaar aan. De private sleutel hou je geheim. Een vingerafdruk van je publieke sleutel (20-bytes hash) is je adres. Met dit adres als pseudoniem ben je gekend op de blockchain. Anderen kunnen dan cryptogeld storten naar dit adres en met je private sleutel kun je dit geld transfereren naar andere adressen, kun je smart contracts publiceren en/of gebruiken.

 

Maar ook een contract heeft een adres en is in staat om cryptogeld te ontvangen, vast te houden en te spenderen! In dit geval spreken we van een contract account. Wanneer een smart contract geld ontvangt, zonder dat expliciet gevraagd wordt om een bepaalde functie in het smart contract uit te voeren, dan wordt de basisfunctie uitgevoerd. Die noteren we als: function (){…}.

 

Wanneer een externe account de functie splitDAO() oproept, zoals in figuur 3, kan onrechtstreeks de payOut()-functie opgeroepen worden, die een bedrag: (_amount) naar het adres van de oproeper stort. Pas nadien zal de functie splitDAO() o.a. de balans van de gebruiker in het smart contract overeenkomstig op nul zetten.

 

 

Het loopt fout wanneer de oproeper van de functie splitDAO() geen externe account is, maar zélf een contract account. Daardoor wordt een recursieve aanval mogelijk, zoals geïllustreerd in figuur 4.

 

 

Deze aanval kan een tijdje doorgaan zonder dat de laatste regels van de splitDAO()-functie uitgevoerd worden – dus zonder dat de balans van het aanvallende contract (balances[msg.sender]) op nul wordt gezet en waardoor steeds hetzelfde bedrag naar het aanvallende contract gestort wordt.

 

 

Uiteindelijk stopt de uitvoering: hetzij omdat het geld dat de aanvaller meestuurt om code uit te voeren is opgebruikt, hetzij omdat de stack-limiet is bereikt, hetzij omdat er geen geld meer in The DAO aanwezig is. Behalve in het laatste geval kan de aanval probleemloos herhaald worden.

 

Conclusies

 

Dit artikel gaat in op twee programmeervalkuilen in Ethereum smart contracts. Er zijn nog heel wat andere voorbeelden van – achteraf gezien – triviale bugs, waarmee soms veel geld verloren ging. In november 2017 ging nog zo’n 300 miljoen dollar verloren. Om het risico op bugs te reduceren laat u uw smart contract voor publicatie dus best nakijken door een deskundige.

 

Bovendien blijven ook klassieke aanvallen bestaan, waarbij de aanvaller de website van een bedrijf hackt en het adres van een smart contract van het bedrijf vervangt door een adres van zijn eigen smart contract. Ook phising blijft een klassieker: de aanvaller stuurt een mail die afkomstig lijkt van een serieus bedrijf, met de vraag om cryptogeld te investeren in een interessant smart contract. Uiteraard is dit niet het smart contract van het bedrijf, maar wel van de aanvaller.

blockchainblogbusinessethereumSmals Researchsmart contracts

Gerelateerde artikelen

Volg ons

Het is Black Friday bij bol.com!

Het is Black Friday bij bol.com!

Deals scoren