Guia definitiva de seguretat intel·ligent dels contractes EOS. La comunitat criptogràfica es va tornar escèptica quan el ICO més gran del món, EOS es va llançar el juny de 2018 i es va congelar durant 2 dies a causa d’un error de programari. Però avançar ràpidament 4 mesos i EOS avui suposa més de doblar les transaccions que fa avui Ethereum. Mitjançant la promesa de transaccions més ràpides i gratuïtes, el Dapp més alt d’EOS compta amb uns 13.000 usuaris actius diaris en comparació amb només 2.000 del Dapp més alt d’Ethereum.

Seguretat intel·ligent dels contractes EOS

A càrrec de Rohan Agarwal

Algunes vulnerabilitats generals dels contractes intel·ligents són aplicables a gairebé totes les plataformes. Igual que Ethereum, els contractes intel·ligents escrits a EOS han de ser auditats abans de publicar-se a la xarxa principal. Els errors greus del contracte es poden aprofitar quan els contractes no tenen prou batalla. En aquesta guia, us ajudarem a evitar les trampes més habituals a l’hora de fer la següent dApp killer a EOS.

Abans de llegir la guia, és important conèixer alguna informació prèvia sobre el desenvolupament d’EOS que us serà útil mentre llegiu la guia. El coneixement de C ++ és imprescindible. El millor lloc per començar amb el desenvolupament de contractes intel·ligents és el propi EOSIO documentació

Tractar amb el despatx ABI

extern "C" {

aplicació nul·la (receptor uint64_t, codi uint64_t, acció uint64_t) {

class_name aquest contracte (receptor);

if ((codi == N (eosio.token)) && (acció == N (transferència))) {

execució_acció (&aquest contracte, &nom_classe :: transferència);

tornar;

}

si (codi! = receptor) torna;

commutador (acció) {EOSIO_API (class_name, (action_1) (action_n))};

eosio_exit (0);

}

}

La imatge anterior és un codi de mostra d’un distribuïdor ABI modificat. Un despatxador ABI més senzill, tal com es mostra a continuació, s’utilitza per gestionar més fàcilment el contracte.

EOSIO_ABI (class_name, (action_1) (action_n));

El despatxador / reenviador ABI permet al contracte escoltar els esdeveniments de transferència d’eosio.token entrants, així com les interaccions normals amb el contracte intel·ligent. És important vincular cada acció i codi clau per complir els requisits, per evitar trucades anormals i il·legals.

Un exemple seria el hack que li va passar a dApp Casino EOSBet a causa d’un error en el seu codi font de reenviament ABI.

if (codi == auto || codi == N (eosio.token)) {

TIPUS aquest contracte (auto);

commutador (acció) {

EOSIO_API (TIPUS, MEMBRES)

}

}

La verificació anterior al controlador d’acció d’aplicació del codi font de reenviament ABI va permetre a un atacant passar per alt la funció eosio.token :: transfer () i trucar directament a la funció contract :: transfer () sense transferir EOS al contracte abans de col·locar el aposta. Per pèrdues, no se li pagava res, però no perdia res. No obstant això, per les victòries se li va pagar EOS real del contracte.

Van solucionar l’error anterior afegint una comprovació de l’acció de transferència de contracte eosio.token abans que les sol·licituds d’acció entrant al contracte.

if (codi == auto || codi == N (eosio.token)) {

if (acció == N (transferència)) {

eosio_assert (codi == N (eosio.token), "Heu de transferir EOS");

}

TIPUS aquest contracte (auto);

commutador (acció) {

EOSIO_API (TIPUS, MEMBRES)

}

}

És important utilitzar la declaració require_auth (compte); en accions que només voleu que executi el compte autoritzat. require_auth (_self); s’utilitza per autoritzar només el propietari del contracte a signar la transacció

Autorització en Accions

testimoni buit :: transferència (nom_compte des de, nom_cont a, quantitat de recursos)

{

auto sym = quantity.symbol.name ();

requereix_recipient (de);

requereix_recipient (a);

pagador automàtic = has_auth (to)? a: de;

sub_equilibri (a partir de, quantitat);

afegir_saldo (a, quantitat, pagador);

}

El codi de mostra anterior permet a qualsevol persona trucar a l’acció. Per resoldre-ho, utilitzeu require_auth (de); declaració per autoritzar el pagador a convocar l’acció.

Intenteu evitar modificar el contracte eosio.token

Un hacker de barret blanc recent ho va aconseguir reclamar 1.000 milions de fitxes d’un dapp a causa d’una trucada de mètode mal provada al seu contracte eosio.token. El Dapp Se7ens (ara inactiu) va declarar un nou mètode dins del contracte eosio.token per llançar les seves fitxes als comptes d’usuari. El contracte no sol·licitava l’emissió ni l’acció de transferència del contracte eosio.token per reflectir els canvis i, per tant, els fons apareixien màgicament als comptes dels usuaris. En segon lloc, es van oblidar de verificar l’import del mètode abans de la transferència, cosa que va permetre al pirata informàtic reclamar 1.000 milions de les seves fitxes durant el procés..

A part de canviar l’oferta màxima i el símbol del testimoni, és recomanable evitar modificar-lo per a funcions personalitzades, ja que els errors del contracte eosio.token poden ser fatals. Per tal de facilitar un llançament aeri de manera segura, transfereixi les fitxes de llançament a un compte separat i distribueix-lo des d’allà.

Modificació de les propietats de la taula multiíndex

Actualment, EOS emmagatzema dades en una base de dades de memòria compartida per compartir-les entre accions.

struct [[eosio :: table]] persona {

clau de nom_compte;

std :: string first_name;

std :: string cognom;

std :: string street;

std :: string city;

std :: estat de la cadena;

uint64_t primària_clau () const {clau de retorn; }

};

typedef eosio :: multi_index<N (persones), persona> adreça_índex;

El codi de mostra anterior crea una taula multi_index anomenada persones que es basa en l’estructura de dades d’una sola fila d’aquesta taula mitjançant la persona struct. EOS actualment no permet la modificació de les propietats de la taula un cop es desplega. eosio_assert_message error afirmació serà l’error que es llançarà. Per tant, les propietats han de ser completament pensades abans del desplegament de la taula. Altrament, cal crear una taula nova amb un nom diferent i extremar la precaució en migrar de la taula antiga a la nova. No fer-ho pot provocar la pèrdua de dades.

Comprovació de desbordament numèric

En fer operacions aritmètiques, els valors poden desbordar-se si les condicions de la frontera no es comproven prou amb responsabilitat, cosa que provoca la pèrdua de recursos dels usuaris.

transferència nul·la (símbol nom_símbol, nom_compte des, noms_cont fins, saldo uint64_t) {

require_auth (de);

compte des del compte;

eosio_assert (is_balance_within_range (balance)), "saldo no vàlid");

eosio_assert (saldo > 0, "ha de transferir saldo positiu"); uint64_t import = saldo * 4; // Desbordament de multiplicació

}

Al codi de mostra anterior, usant uint64_t indicar el saldo de l’usuari pot provocar desbordament quan es multiplica el valor. Per tant, eviteu utilitzar-lo uint64_t per denotar saldos i realitzar-hi operacions aritmètiques en la mesura del possible. Utilitzeu l’estructura d’actius definida a l’eosiolib per a operacions en lloc del saldo exacte que s’encarrega de les condicions de desbordament.

Tenir cura dels supòsits del contracte

Hi haurà supòsits que requeriran afirmacions durant l’execució del contracte. L’ús de eosio_assert s’encarregarà de les condicions prèviament i detindrà l’execució de l’acció específica si fallen les afirmacions. Com un exemple –

void assert_roll_under (const uint8_t& roll_under) {

eosio_assert (roll_under >= 2 && roll_under <= 96,

"rodar sota desbordament, ha de ser superior a 2 i inferior a 96");

}

La declaració assert anterior suposa que roll_under integer és superior a 2 & menys de 96. Però si no és així, llenceu el missatge anterior i atureu l’execució. No descobrir casos raconats com l’anterior pot esdevenir catastròfic per a la casa que estableix les regles.

Generació de nombres aleatoris vertaders

Generar números aleatoris reals a la cadena de blocs EOS continua sent un risc si no es fa amb precisió. Si no ho feu correctament, l’adversari predirà els resultats i jugarà tot el sistema en el procés. Serveis com Oracalize.it existeix per proporcionar números aleatoris des d’una font externa, però són cars i tenen un únic punt d’error. Les persones han utilitzat les variables contextuals de Blockchain (número de bloc, segell de blocs, etc.) en el passat per generar el número aleatori en el contracte intel·ligent d’Ethereum, però ha estat jugava abans. Per fer la generació correctament, el programa ha de proporcionar una mena d’atzar combinat que cap de les parts podia controlar sol. Una de les millors maneres possibles actualment és un mètode suggerit pel mateix Dan Larimar quan es genera un nombre aleatori entre dues parts.

Bloc BountyOne: seguretat intel·ligent dels contractes EOS

string sha256_to_hex (const checksum256& sha256) {

tornar a_hex ((char *) sha256.hash, sizeof (sha256.hash));

}

string sha1_to_hex (const checksum160& sha1) {

torna a_hex ((char *) sha1.hash, sizeof (sha1.hash));

}

plantilla <classe T>

Inline void hash_combine (std :: size_t& llavor, const T& v) {

std :: hash<T> hasher;

llavor ^ = hasher (v) + 0x9e3779b9 + (llavor << 6) + (llavor >> 2);

}

El codi de mostra anterior proporciona una generació de nombres aleatoris optimitzada entre 1 i 100. seed1 és la seed house i seed2 és la seed de l’usuari anterior. Com a referència, Dappub i EOSBetCasino han obert els seus contractes complets amb la implementació d’un generador de números aleatoris d’un joc de daus just entre el jugador i la casa (desenvolupador).

uint8_t compute_random_roll (const checksum256& seed1, const checksum160& llavor2) {

size_t hash = 0;

hash_combine (hash, sha256_to_hex (seed1));

hash_combine (hash, sha1_to_hex (seed2));

retorn hash% 100 + 1;

}

EOSBet ha tingut recentment tornat a piratejar de 65.000 EOS quan un adversari va enganyar el seu contracte eosio.token per enviar EOS a la seva cartera sempre que realitzava transaccions entre les seves pròpies carteres. El codi de contracte eosio.token notifica tant el remitent com el receptor de tokens EOS que hi ha tokens entrants. Imitar el comportament & faciliteu el pirateig, l’adversari va crear dos comptes, suposem que A & B. A tenia un contracte intel·ligent amb una acció amb declaració require_recipient (N (eosbetdice11)). Quan A va facilitar la transacció d’A a B mitjançant la trucada d’acció, va notificar-ho a funció de transferència al contracte com si la trucada hagués estat del contracte eosio.token. Com que no hi va haver cap transferència real d’EOS al contracte, cada vegada que el pirata informàtic perdia una aposta, no perdia res, però va ser recompensat quan va guanyar l’aposta. Per tant, comprovar només el nom del contracte i el nom de l’acció no és suficient.

Comprovacions de notificacions de contractes

Per mitigar el problema, la funció hauria de comprovar si el contracte és o no el receptor de les fitxes.

eosio_assert (transfer_data.from == _self || transfer_data.to == _self, "Ha de ser una transferència entrant o sortint");

Quines són les pràctiques recomanades que cal seguir mentre es desenvolupa un contracte intel·ligent a EOS?

Els errors són part inevitable de qualsevol programari. Les seves conseqüències s’amplifiquen en un entorn descentralitzat, especialment si implica transaccions de valor. A part de les garanties específiques d’EOS comentades anteriorment, aquí teniu algunes de les precaucions generals i les pràctiques recomanades que els nous desenvolupadors de contractes intel·ligents haurien de tenir en compte:

  1. Sempre auditoria el contracte independentment de les empreses d’auditoria de contractes intel·ligents de tercers abans de publicar-lo a mainnet.
  2. Feu la depuració necessària de Caveman (única forma de depurar el contracte actualment) del contracte abans de llançar-la al testnet. La documentació EOSIO té un gran guia per això.
  3. Establiu la taxa de transferència límit en les retirades per evitar pèrdues excessives els primers dies de llançament de mainnet. Teniu un programa de recompensa d’errors per a la divulgació responsable per part de pirates informàtics.
  4. Tingueu un interruptor per bloquejar el contracte quan es detecti un error.

Per implementar-lo, persistim un indicador a la taula multi_index. Establim la bandera mitjançant una acció que només pot trucar el propietari del contracte. I després comprovem en cada acció pública si la bandera està configurada per congelar-se o no. A continuació es mostra una implementació de la funció.

struct st_frozen {

uint64_t congelat;

};

typedef singleton<N (congelació), st_frozen> tb_frozen;

tb_frozen _frozen;

uint64_t getFreezeFlag () {

st_frozen frozen_st {.frozen = 0};

tornar _frozen.get_or_create (_self, frozen_st);

}

void setFreezeFlag (const uint64_t& pFrozen) {

st_frozen frozen_st = getFreezeFlag ();

frozen_st.frozen = pGelat;

_frozen.set (frozen_st, _self);

}

// Acció pública

congelació nul·la () {

require_auth (_self);

setFreezeFlag (1);

}

// Acció pública

void unfreeze () {

require_auth (_self);

setFreezeFlag (0);

}

// qualsevol acció pública

acció nul·la (…) {

eosio_assert (getFreezeFlag (). congelat == 1, "El contracte està congelat!");

}

  1. Estigueu al dia sobre les millores de seguretat a les biblioteques o les divulgacions de vulnerabilitats a la plataforma. Actualitzeu les biblioteques immediatament quan sigui necessari.
  2. Obriu el codi de contracte de codi obert com a mínim perquè es mantingui la justícia en el joc i els desenvolupadors independents puguin ajudar a detectar errors molt més ràpidament.

EOS Smart Contract Security: Conclusió

Han passat només cinc mesos des del llançament d’EOS, però ha superat les expectatives. Les compensacions que ha fet – DPOS, contractes intel·ligents mutables, 21 nodes miners, etc., s’han enfrontat sens dubte a fortes crítiques dels maximalistes de la descentralització. Tot i això, no ha impedit que les dApps basades en Ethereum passin a EOS donada l’escalabilitat que la plataforma els ofereix avui. Encara no s’ha decidit si EOS o Ethereum guanya la guerra, però certament EOS ha guanyat la batalla. I seguirà igual fins que Ethereum aconsegueixi l’escalabilitat que el món necessita per executar “The World Computer”.

_________________________________________________________________________________________

Aquest article va ser escrit per Rohan Agarwal

Bio – #Android Dev # Emprenedor # Blockchain Dev & Investigador cofundador @ Cypherock.com: una cartera de maquinari segura per a telèfons intel·ligents.

Linkedin – https://www.linkedin.com/in/rohanagarwal94/

Github – https://github.com/rohanagarwal94

Twitter – https://twitter.com/rohanagarwal94

Mike Owergreen Administrator
Sorry! The Author has not filled his profile.
follow me