Dieses Dokuwiki verwendet ein von Anymorphic Webdesign erstelltes Thema.
Prijevodi ove stranice:

Sigurnosne prijetnje programskog jezika Solidity

Sažetak

U zadnjih nekoliko godina jedno od najpopularnijih područja globalno bila je tehnologija blockchain i kakve teme vezane uz tehnologiju blockchain, s najvećim naglaskom na kriptovalute, Bitcoin, pametne ugovore i Ethereum. Tržišna je vrijednost ove tehnologije u vrlo kratkom vremenskom roku eksplodirala te privukla brojne ljude diljem svijeta da se počnu zanimati za ove teme i da se uključe u vezane procese - ulaganje u kriptovalute, rudarenje kriptovaluta, osmišljavanje pametnih ugovora, razvoj na Ethereum platformi i slično.

S javljanjem pametnih ugovora pojavila se potreba za prilagođenim programskim jezicima koji bi olakšavali razvijanje istih u skladu sa zahtjevima tehnologije blockchain i pripadajuće platforme na kojoj se ugovor razvija. U tom je kontekstu nastao i programski jezik Solidity, jedan od vodećih svjetskih jezika za pametne ugovore.

Ovaj će seminar kratko razraditi pitanje što je to Solidity i čemu služi, a koncentrirat će se na sigurnosne prijetnje unutar Solidity-ja. Seminar će potaknuti pitanje zašto treba obraćati pozornost na sigurnosne prijetnje te će se detaljno razraditi tri primjera postojećih sigurnosnih prijetnji, kako se protiv njih boriti i, ukoliko je moguće, kako ih spriječiti. Predstavit će se i primjeri iz stvarnog svijeta koji kazuju kakve su efekte upravo te prijetnje imale i kakvi su napadi proizašli iz njih .

Svrha seminara je upozoriti čitatelja na sigurnosne prijetnje te ga pozvati na aktivno razmišljanje o sigurnosti za vrijeme razvijanja pametnih ugovora.

Ključne riječi: Solidity, sigurnost, sigurnosne prijetnje, pametni ugovori

Uvod

Solidity je objektno orijentirani programski jezik namijenjen za pisanje pametnih ugovora. Najpoznatiji je po činjenici da je upravo on primarni jezik na jednoj od najpoznatijih blockchain platforma - na Ethereumu, ali koristi se i na raznim drugim blockchain platformama. Prvi put se pojavio u kolovozu 2014. godine.

Pametni ugovori su javni i nepromjenjivi računalni programi koji su pohranjeni na blockchainu. Mogu se javno i pouzdano izvršavati koristeći blockchain. Da bi se program uopće mogao pohranjivati i izvršavati na blockchainu u obliku pametnog ugovora, mora se pridržavati pravila i poštivati ograničenja tehnologije blockchain. Svrha Solidity-ja je da omogući programerima lako i intuitivno pisanje pametnih ugovora dok Solidity interno rješava dio ograničenja i pravila zadanih blockchainom.

Najpopularnije primjene pametnih ugovora programiranih u Solidity-ju su implementacije glasovanja, grupnog financiranja (crowdfunding), aukcija i novčanika s više potpisa (multi-signature wallets).

Iako je široko raširen, Solidity je još uvijek u ranoj razvojnoj fazi (trenutna najnovija verzija je 0.6.1), a to ukazuje na puno prostora za sigurnosne prijetnje. Ovaj će seminar razmotriti nekoliko zanimljiviih otkrivenih sigurnosnih propusta te službena ili potencijalna rješenja za sprječavanje istih. Logo Solidity-ja vidljiv je na sljedećoj slici.

Višestruki ulazak (Re-Entrancy)

Za razumijevanje ovog napada, potrebno se upoznati s pojmom fallback funkcije. Fallback funkcija je funkcija koja se izvršava kada neki ugovor primi ethere bez ikakvih drugih podataka povezanih s tom transakcijom. Također, izvršavaju se kad identifikator funkcije ne odgovara niti jednoj funkciji dostupnoj u pametnom ugovoru ili kada nikakvi podatci nisu dani pri pozivu funkcije. Fallback funkcije nemaju ime, ne mogu primati argumente, ne mogu vraćati ništa te u jednom ugovoru postoji najviše jedna fallback funkcija.

Ovaj je napad omogućen kada pametni ugovor šalje sredstva (Ethere, Wei-je ili neku drugu kriptovalutu) na nepoznatu adresu pozivom odgovarajuće funkcije nepoznate adrese / primatelja. Napadač pažljivom konstrukcijom svog ugovora na toj nepoznatoj adresi može umetnuti zlonamjerni kod koji će se pokretati pri slanju sredstava na tu nepoznatu adresu. Točnije, u ovom napadu, taj će zlonamjerni kod ponovno pozvati funkciju napadnutog ugovora prije nego što se prošla iteracija ugovora izvršila do kraja te na taj način iskoristiti ranjivi ugovor.

Na sljedećim slikama nalazi se primjer. U primjeru su dva pametna ugovora - napadnuti ugovor EtherStore te ugovor napadača Attack. Detaljna objašnjenja nalaze se ispod slika.

Napadnuti ugovor

U ovom primjeru EtherStore je napadnuti ugovor, a Attack je ugovor napadač.Originalna željena funkcionalnost ugovora EtherStore je da pohranjuje riječnik stanja računa svojih klijenata. Neki klijent može pohraniti određenu količinu valute (wei-ja) koji će se dodati na njegovo stanje računa, te može podizati wei-je sa svog računa. Naravno, u metodi za podizanje novaca, pametni ugovor EtherStore provjerava je li iznos koji se pokušava podići manji od stanja računa klijenta (naravno, nije moguće podići više sredstava nego što postoji na računu) te postoji ograničenje da svaki klijent može podići sredstva maksimalno jednom u tjedan dana. Ova su ograničenja vidljiva u linijama 14 i 16 pametnog ugovora EtherStore. U liniji 17, EtherStore šalje sredstva klijentu te u linijama 18 i 19 osvježava stanje računa i vremensku oznaku zadnjeg podizanja novca.

Napadač prvo pohranjuje određena sredstva (1 wei) na svoj račun u EtherStore, a zatim pokreće funkciju za podizanje tih sredstava - također 1 wei. Zahtjev za podizanje sredstava uspješno prolazi sve provjere te se u liniji 17 ugovora EtherStore sredstva (1 wei) šalju napadaču. Upravo ovdje događa se sigurnosni propust. Linija 17 zapravo pokreće fallback funkciju ugovora Attack, a u fallback funkciji nalazi se zloćudni kod. Taj kod ponovno poziva funkciju EtherStore-a za podizanje sredstava (ponovno jednog wei-a). Problem je u činjenici što su sredstva prethodnog poziva već na računu napadača, a novi poziv funkcije withrawFunds kreće se izvršavati prije nego što je prethodni poziv stigao osvježiti potrebne varijable stanja na računu i vremenske oznake podizanja novca. Tu zapravo ulazimo u petlju koja, wei po wei, potpuno prazni ukupan račun ugovora EtherStore, uz uspješne provjere svih varijabli u svakom pozivu.

Ovo je jedan od većih i važnijih sigurnosnih prijetnji koje treba imati na umu pri dizajniranju pametnih ugovora. Ovakvo neželjeno ponašanje može se spriječiti na više načina. Jedno od rješenja je korištenje funkcije transfer() pri slanju sredstava vanjskim ugovorima. Funkcija transfer sa svojim pozivom šalje dovoljno gas-a (platne jedinice za izvršavanje funkcija) da bi se sredstva poslala, ali nedovoljno da bi vanjski ugovor izveo operaciju poput zvanja nekog drugog ugovora - to automatski sprječava ponovno pozivanje napadnutog ugovora. Još jedno rješenje je koristiti “checks-effects-interactions” slijed događaja pri dizajniranju funkcija pametnih ugovora. Ova metoda predlaže da se u svakoj funkciji prvo naprave provjere i zadovolje uvjeti da bi se funkcionalnost ugovora izvršila, zatim da se osvježe sve varijable (kao da je akcija već izvršena), a tek se na kraju akcija stvarno izvrši. Na taj način sprječava se ovakav napad jer već u drugom pozivu ugovora, uvjeti neće biti zadovoljeni.

Najpoznatiji napad ove vrste je napad na The DAO organizaciju (Decentralized autonomous organization). U tom trenutku, njihov pametni ugovor držao je na sebi više od 150 milijuna dolara. Ovakvim napadom napadač je uspio trećinu svih sredstava prebaciti na vanjski račun. Kako bi ispravili grešku, Ethereum zajednica odlučila se na kontroverzno rješenje - napraviti granu na Ethereum blockchainu i virtualno vratiti sva sredstva na originalni ugovor. Kao posljedica, dan danas postoje dva službena Ethereum blockchaina - Ethereum i Ethereum Classic (na Ethereum classic još se vidi posljedica napada).

Aritmetički overflow i underflow

Ovaj se napad bazira na postojanju overflowa i underflowa. Overflow i underflow javljaju se kao posljedica načina na koji računalo zapisuje brojeve u memoriju. Za zapis svakog tipa podatka rezerviran je određen broj bitova u memoriji. Primjerice za tip podatka uint8 rezervirano je 8 bitova te je posljedično u taj tip podatka moguće zapisati samo brojeve u rasponu [0,255]. Kada bi u varijabli tipa uint8 bio zapisan broj 255 i kada bismo mu pribrojili 1, umjesto 256 u varijabli bi bila zapisana vrijednost 0. Analogno, kada bismo varijabli sa vrijednošću 0 pokušali oduzeti 1, dobili bismo 255, a ne -1. Ova je pojava dovela do nekih ozbiljnih sigurnosnih prijetnji u razvoju pametnih ugovora.

Na sljedećoj slici nalazi se primjer objašnjen u tekstu ispod slike.

Zamišljena funkcionalnost prikazanog pametnog ugovora TimeLock je pohrana novca te mogućnost podizanja uz minimalnu vremensku odgodu od jednog tjedna. Uporabom funkcije increaseLockTime, klijent može proizvoljno povećati željeno vrijeme na koje će sredstva biti zaključana. Upravo je u toj funkciji sigurnosna prijetnja - poznavanjem činjenice da varijabla tipa uint može sadržavati brojeve zapisane maksimalno sa 256 bitova te poznavanjem trenutnog vremena na koje su sredstva zaključana, vrlo je lako izračunati potreban broj sekundi koji treba pribrojiti da bi se dogodio overflow te da bi se sredstva otključala upravo sada.

Sličan bi problem nastao kada bi se primjerice s računa na kojem je dostupno 100 wei-ja uspješno skinuo 101 wei. U tom slučaju dogodio bi se underflow i odjednom bi stanje računa napadača postalo izuzetno veliko.

Trenutno rješenje za sprječavanje ovakvih napada je korištenje (ili razvoj) matematičkih paketa koji bi zamijenili standardne matematičke operacije te koji bi provjerama sprječavali pojavu overflowa i underflowa. Primjer takve knjižnice je Safe Math Library kojeg razvija OppenZeppelin.

Primjer ovog napada u stvarnom svijetu je konstrukcija ponzijeve sheme na Ethereumu (PoWHC - Proof of Weak Hands Coin), čiji su kreatori zaboravili na problem overflowa i underflowa te posljedično izgubili 866 Ethera sa pametnog ugovora.

Vidljivosti funkcija

Vidljivost funkcije određuje skup pozivatelja koji imaju mogućnost pokrenuti funkciju. Standardna vidljivost funkcija u Solidity-ju je “public”, to jest ukoliko nije specifirana vidljivost, vidljivost je automatski javna i bilo tko može pozvati funkciju - bilo koji korisnik, drugi ugovori, funkcija može biti pozvana interno ili ju mogu pozvati vanjski korisnici i ugovori. Solidity specificira četiri vrste vidljivosti - external, public, internal i private. Vanjske (external funkcije) ne mogu biti pozivane interno, javne funkcije (public) može pozvati bilo tko, interne (internal) funkcije mogu biti pozvane samo interno iz trenutnog ugovora ili ugovora koji nasljeđuje bazni ugovor u kojem je funkcija, a privatne funkcije (private) mogu biti pozvane samo iz trenutnog ugovora (ugovori koji nasljeđuju bazni ugovor ne mogu pozivati privatne funkcije baznog ugovora).

Ova je ranjivost prilično trivijalna i poznata i iz drugih programskih jezika, no svejedno programeri često smetnu s uma vidljivost funkcija te se posljedično događaju sigurnosni propusti. Problem je u činjenici što, ukoliko nismo specificirali vidljivost, vidljivost funkcije je public, upravo najopasnija verzija vidljivosti. Stoga se u slučaju nemara ili zaborava lako nađemo u problemu.

Proučimo trivijalni primjer:

Svrha ovog ugovora je dodijeliti nagradu sretnim dobitnicima - korisnicima sa adresom čijih su zadnjih 8 hex znakova nule. Ukoliko se provjera uspješno izvrši, poziva se funkcija _sendWinnings koja šalje pobjedniku novčanu nagradu. Problem je u tome što je autor ugovora HashForEther zaboravio specificirati vidljivost funkcije _sendWinnings na privatnu te bilo tko može jednostavno pozvati izravno tu funkciju i dobiti novčanu nagradu.

Kako bi se izbjegla ova neugodnost, dobra je praksa uvijek specificirati vidljivost svim funkcijama, čak i javnim funkcijama, kako bi programer uvijek razmislio koja funkcija treba imati kakvu vidljivost i rjeđe nailazio na ovakav problem.

Primjer iz stvarnog svijeta je napadač koji je uočio ovakav propust u Parity multi-signature novčaniku na Ethereum platformi te iskoristivši tu ranjivost prebacio vrtoglavih 31 milijun dolara vrijednosti u Etheru na svoj račun u samo nekoliko minuta. Da napad nije vrlo brzo uočen i da je napadač imao još nekoliko sati, uspio bi otići sa 180 milijuna dolara vrijednosti sa svih ranjivih novčanika na mreži. Napad je spriječen tako da je grupa dobroćudnih hakera, uočivši napad, brzo analizirala isti te su brzom reakcijom sami hakirali preostale novčanike s navedenom ranjivošću i sami ukrali preostalih 150 milijuna dolara prije nego što je to uspio učiniti napadač. Nakon reorganizacije ranjivog koda i uklanjanja sigurnosne prijetnje, dobroćudni su napadači vratili ukradene iznose prethodnim vlasnicima. Nažalost, preostalih 31 milijun dolara nije se mogao vratiti prvobitnim vlasnicima.

Iako ovaj sigurnosni propust zvuči trivijalno, ovaj primjer, a vjerojatno i drugi primjeri, ipak ukazuju na ozbiljnost ovog problema pogotovo u ovom kontekstu gdje pametni ugovori zaista drže novčana sredstva na sebi te postoje ozbiljne posljedice od napada.

Zaključak

Ovaj je seminar razradio samo tri sigurnosne prijetnje, međutim postoji mnoštvo drugih raznih sigurnosnih prijetnji u programskom jeziku Solidity. Neke su prijetnje već nađene te već postoje rješenja i preporučene dobre prakse kako bi se te probleme spriječilo, a mnogi problemi tek čekaju da budu nađeni i iskorišteni. Pogotovo s obzirom na činjenicu da je i ova tehnologija relativno mlada, a pogotovo programski jezik Solidity. Puno govori i već spomenuta činjenica da Solidity još uvijek nije dočekao službenu verziju 1, nego je trenutna zadnja verzija 0.6.1.

Unatoč nekolicini sigurnosnih prijetnji, Solidity je popularan programski jezik u blockchain svijetu i svijetu pametnih ugovora te je donio puno više dobroga nego što je narušeno napadima. Kao i u svakoj tehnologiji, korisnik mora biti upoznat sa potencijanim opasnostima, truditi se razvijati ugovore u skladu s najboljim praksama te voditi računa da uvijek radimo u najnovijoj verziji Solidity-ja (pogotovo u ovoj ranoj fazi), jer je velika vjerojatnost da svaka nova verzija zakrpava neke postojeće nađene sigurnosne propuste.

Literatura

racfor_wiki/razno/sigurnosne_prijetnje_solidity.txt · Zadnja izmjena: 2023/06/19 18:17 (vanjsko uređivanje)
Dieses Dokuwiki verwendet ein von Anymorphic Webdesign erstelltes Thema.
CC Attribution-Share Alike 4.0 International
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0