Finanza decentralizzata e sfide di sicurezza: gli Smart Contracts

Nell’articolo precedente ho spiegato che cos’è la finanza decentralizzata (DeFi) e le sue applicazioni fornendo una panoramica sullo Smart Contract e il protocollo Compound, di seguito mi concentrerò sui problemi legati alla sicurezza.

Sicurezza degli Smart Contracts

Il primo aspetto relativo alla sicurezza riguarda lo smart contract in sé. Lo smart contract è a tutti gli effetti una applicazione, un programma; è un codice che rappresenta le regole del gioco, come i vari attori possono interagire in maniera legittima con lo smart contract, ed è codificato all’interno di un programma che, a basso livello, è compatibile con la Ethereum Virtual Machine, specifica funzionale di una macchina astratta che esegue il programma dello smart contract.

Su un piano più alto gli smart contract sono implementati in linguaggi di alto livello, il più famoso dei quali è Solidity.

A tutti gli effetti uno smart contract è però un programma ed è, quindi, soggetto ad errori.

I programmi possono essere scritti male per tanti motivi, perché sono progettati o implementati male; tali errori o bug – e questo non riguarda ovviamente le sole applicazioni di finanza decentralizzata, ma i programmi in generale – possono trasformarsi in vulnerabilità, in scenari che utenti maliziosi dello smart contract possono sfruttare per ottenere dei vantaggi, come ad esempio effettuare attacchi contro gli smart contract facendo leva sugli errori di progettazione o programmazione.

Gli smart contract non sono esenti da questo tipo di problematiche: ci sono stati casi famosissimi di smart contract mal scritti che hanno causato gravi problemi agli autori e agli utenti. Ne deriva che essere certi che uno smart contract sia stato correttamente implementato rappresenta un aspetto molto importante.

Per realizzare uno smart contract corretto rispetto ad una specifica, esistono due strategie. Una riguarda l’utilizzo di blocchi base, che realizzano pezzi di funzionalità di uno smart contract, per poi mettere insieme, attraverso dei meccanismi ben definiti, questi pezzi fondamentali per creare un oggetto più complesso e dalle funzionalità più ricche; che però, essendo stato costruito su oggetti considerati affidabili e sicuri, vanno a realizzare un prodotto a sua volta considerato affidabile e sicuro.

Questo approccio offre un’assurance molto forte circa la sicurezza di ciò che si è realizzato, affinché esegua in maniera corretta la specifica cui era destinato: quindi, sembrerebbe essere l’approccio perfetto.

Il problema e i limiti di questo approccio risiedono nel fatto che non tutto è costruibile attraverso la composizione di elementi base semplici e sicuri.

Esistono casi in cui bisogna scrivere uno smart contract che non è, purtroppo, realizzabile utilizzando semplicemente questi blocchi base; in questo scenario sarò costretto a inserire del codice che non proviene da questi blocchi fondamentali e che quindi inquina e “degrada” la mia assurance sull’oggetto finale.

Il secondo approccio, che vediamo negli altri due punti della slide, riguarda l’ex-post assessment. Quindi in questo caso si scrive lo smart contract, in maniera coscienziosa, in una specie di draft e questa “bozza” dello smart contract viene analizzata da alcuni tool – i due più importanti sono ConsenSys/Mythril e Certora – i quali svolgono un assessment molto complesso basato su concetti che riguardano la prova matematica di correttezza di una specifica rispetto allo smart contract.

Vediamo citato anche il framework utilizzato da questi due tool, che effettuano un assessment rispetto a una libreria di vulnerabilità note.

La storia degli smart contract è infatti abbastanza ricca: essi esistono ormai da svariati anni e ciò ha permesso di accumulare una serie di scenari di sicurezza che rappresentano altrettante vulnerabilità, poi inserite all’interno di una libreria.

L’assessment serve quindi a capire se lo smart contract che è stato scritto contenga delle vulnerabilità note. Ciò fa già intuire il limite di questo tipo di tool, perché essi consentono, appunto, di fornire un’assurance solo rispetto a vulnerabilità già note fino a quel momento.

Non è detto però che lo smart contract realizzato sia totalmente esente da vulnerabilità e realizzi la specifica in maniera corretta, perché quella specifica potrebbe non essere stata ancora inserita all’interno della libreria dalla quale attingono questi tool.

Quindi in teoria potremmo definire la specifica del nostro smart contract sulla base delle estensioni di questi tool, ma si tratta di un’operazione molto complessa e della quale bisogna valutare il costo, decisamente diverso rispetto a un controllo di tipo standard.

Chiaramente questi due approcci sono ortogonali tra loro: non è detto che l’uno o l’altro debba essere utilizzato in maniera mutuamente esclusiva, potendo invece essere utilizzati insieme. Se è possibile, andrebbe utilizzato al massimo OpenZeppelin, inquinandolo magari con del codice scritto appositamente – del codice custom – e poi passare questo draft di smart contract scritto attraverso questi tools di assessment. Avremo così una doppia assurance – ciascuno ne fornisce una diversa – e, componendo queste due attività insieme, ne risulta un buon sistema per capire se uno smart contract sia sicuro oppure no.

Esistono però anche altri problemi di sicurezza.

Nella slide vedete un esempio di smart contract che realizza un token di tipo ERC-20: se utilizzo OpenZeppelin questo smart contract si realizza in maniera molto semplice generando un token ERC-20 full-fledged.

Quindi, compilando lo smart contract e mettendolo sulla blockchain di Ethereum realizzo effettivamente un nuovo token (come ce ne sono a centinaia già presenti sul mercato) e posso addirittura manipolarli: quindi venderli, comprarli, crearli, perché questo è un token mintable.

Posso creare token attraverso wallet assolutamente standard; Metamask, che implementa appunto l’interfaccia ERC-20, sarà in grado di riconoscere questo token e di effettuare operazioni sui token attraverso gli utenti.

In poche righe di codice, appena sette, ho realizzato un token ERC-20.

La cosa importante è che questo token è realizzato grazie alle componenti fondamentali che OpenZeppelin mette a disposizione, con una ragionevole assurance che il codice lì scritto – e quindi il token che viene implementato – realizzi in maniera corretta una specifica minimale ERC-20.

Passiamo ad altri aspetti di sicurezza. Abbiamo già detto che gli smart contract realizzano degli scenari finanziari, anche molto complessi, in maniera decentralizzata. Capita, però, molto spesso che per realizzare questi scenari si abbia bisogno di apprendere elementi che non si trovano all’interno della blockchain.

La blockchain garantisce l’integrità dello smart contract e in generale dell’intera rete, quindi garantisce che le regole dello smart contract vengano seguite: essa però non può in alcun modo garantire che le informazioni provenienti dall’esterno siano effettivamente affidabili.

Ogni qualvolta si dipende da elementi che provengono dal mondo esterno alla blockchain si crea una dipendenza di trust tra lo smart contract e un attore esterno, perché si tratta di iniettare all’interno della blockchain le informazioni che provengono dal mondo esterno.

Con un’applicazione di finanza decentralizzata che consente di acquistare un pacchetto assicurativo contro, ad esempio, il rialzo del prezzo del petrolio (un tipico contratto future), questo contratto può essere realizzato sulla blockchain in maniera decentralizzata, senza intermediari ma soltanto con l’aiuto di qualcuno – il cosiddetto oracolo – che, dall’esterno, inietta nello smart contract il prezzo del petrolio.

Chiaramente, per essere sicuri che stia iniettando all’interno della blockchain dei dati accurati e affidabili, l’oracolo dovrà essere affidabile a sua volta; l’argomento degli oracoli è molto discusso e da parecchi anni esistono misure volte a mitigare il rischio che l’oracolo si comporti in maniera disonesta, perché l’oracolo può essere esso stesso un membro della comunità finanziaria e quindi avere un bias affinché un contratto si comporti in una certa maniera. Quindi, pur non esistendo garanzie assolute, sono stati ideati dei meccanismi che riducono la dipendenza rispetto a un singolo oracolo.

Il modo più semplice è utilizzare oracoli multipli e avere una specie di regola del consenso, in cui si assume che in un dato istante di tempo non tutti gli oracoli siano disonesti e che, comunque, una certa parte degli oracoli rimanga onesta: se tutti gli oracoli che forniscono il prezzo del petrolio, o perlomeno una certa parte rispetto a una soglia definita nello smart contract, mi dicono che il prezzo del petrolio è x e sono in accordo tra loro – quindi raggiungono un consenso – allora posso fidarmi sul fatto che il prezzo del petrolio sia effettivamente quello.

Chiaramente si assume che in un certo istante di tempo solo una percentuale di oracoli sia disonesta (ad esempio, il 33%) e che quindi un terzo degli oracoli si comporti in maniera disonesta; ma è semplicemente un’assunzione, nessuno garantisce che sia poi effettivamente verificata.

L’altro approccio, non sempre possibile, è prevede di avere un’informazione che lo smart contract possa verificare.

Se per ipotesi affermiamo che nello smart contract, nella dApp che realizza un’applicazione di finanza decentralizzata, si definisce che il prezzo del petrolio deve derivare da Bloomberg (ad esempio utilizzando un’API di Bloomberg in un certo endpoint, che ha una certa URL) l’oracolo può fornire una prova che il colloquio che ha avuto con Bloomberg si sia effettivamente verificato; insieme all’informazione trasmessa, allo smart contract viene dunque inviata anche una prova dell’interazione che l’oracolo ha avuto con la fonte dell’informazione stessa. Lo smart contract verifica questa prova di interazione e, se la verifica va a buon fine, l’informazione viene effettivamente assunta. A questo punto lo smart contract dà seguito a tutti gli effetti, che dovranno essere messi in pratica secondo le norme dello smart contract stesso.

Un ulteriore aspetto di sicurezza riguarda l’immutabilità degli smart contract: una volta inseriti sulla blockchain, questi non possono essere più modificati. Però può succedere di accorgersi, dopo aver immesso lo smart contract sulla blockchain, che esso contiene degli errori che potrebbero rappresentare delle vulnerabilità.

Tradizionalmente esiste un processo di sicurezza informatica, chiamato patch management, per poter modificare il codice dell’oggetto difettoso in maniera da correggere questo difetto per il futuro.

Idealmente in una blockchain questo non è possibile, perché il codice dello smart contract non può essere modificato da nessuno; è una regola fondamentale delle blockchain, che garantisce l’integrità del sistema ma al tempo stesso rappresenta un vincolo non indifferente rispetto a questo tipo di problematiche.

Per correggere un errore in uno smart contract sono allo studio diverse soluzioni: il trend attuale è quello dei cosiddetti contratti proxy.

Proxy contracts, cosa sono e come funzionato

Ovvero contratti che realizzano solo la parte di interfaccia dello smart contract, separata dalla parte di implementazione delle regole dello smart contract, che si trova in un differente contratto. Quindi le dApp, la parte tradizionale di un’applicazione di finanza decentralizzata (per esempio applicazione web), non interagiranno con lo smart contract che realizza e implementa le regole dello smart contract ma interagiranno con questo proxy contract, ovverosia un contratto intermedio che non fa altro che prendere le richieste dell’applicazione web e trasferirle al contratto che poi realizzerà, in effetti, le regole dello smart contract.

In questo modo è possibile successivamente, in caso di bisogno, effettuare un upgrade al codice dello smart contract, cambiare l’indirizzo di destinazione del proxy contract e, in un certo istante di tempo, cambiare l’indirizzo: in questo modo tutte le dApp che stavano utilizzando quello smart contract non applicheranno più il vecchio smart contract, ma utilizzeranno quello nuovo in maniera completamente trasparente.

È importante capire che questa è una problematica significativa. Pensate a cosa potrebbe succedere trovando un problema di sicurezza, una vulnerabilità, all’interno di uno smart contract come Compound, che di per sé non realizza tutto lo stack di un’applicazione di finanza decentralizzata ma la sola parte di smart contract.

Chi gestisce, implementa e fa evolvere Compound non è detto conosca tutte le dApp che utilizzano Compound, perché l’indirizzo di Compound è assolutamente libero: sarebbe dunque molto complicato modificare le dApp per utilizzare un contratto diverso, aggiornato e con una fix di sicurezza rispetto al contratto precedente. In caso ciò non fosse possibile e si realizzasse questo meccanismo del proxy contract ci sarebbero altre problematiche perché, cambiando la destinazione delle richieste verso il proxy compact su un nuovo contratto (che ha una fix di sicurezza), rimarrebbe il problema dello storage.

Il contratto di per sé ha una vita, uno stato in ogni istante di tempo che viene costantemente aggiornato delle transazioni che insistono su questo smart contract; e questo stato deve essere trasferito nel nuovo smart contract, il che è un’operazione non banale.

Per ovviare a questo problema si sta pensando di implementare un ulteriore tipo di contratto: gli storage contract, contratti molto basic, esattamente come un proxy contract che realizza una semplice interfaccia verso un altro smart contract.

Storage contract, cos’è e come funziona

Lo storage contract realizza quello che nell’informatica tradizionale sarebbe un database, un sistema di storage molto semplice.

Per far migrare il proxy contract è necessario farlo puntare al nuovo contratto aggiornato, che non avrà storage e punterà al vecchio storage, quindi al contratto che veniva utilizzato dal vecchio smart contract.

Utilizzando proxy contract e storage contract è possibile realizzare una “aggiornabilità” per correggere errori di sicurezza che è assimilabile a quella dei sistemi tradizionali.

Ciò induce a una maggiore complessità del sistema e, in particolare, quando si deve lanciare una transazione verso il proxy contract si devono in realtà lanciare diverse transazioni verso altri contratti; e questo ha un costo sulla rete Ethereum, perché lanciare la trattazione di altri contratti ha un costo maggiore rispetto a una transazione interna, limitata a un solo contratto.

Questo tipo di operazioni, quindi, ha un costo che va tenuto in considerazione.

Un piccolo addendum rispetto alle precedenti informazioni riguarda la possibilità di far “suicidare” un contratto.

A livello di blockchain, ma non a livello di smart contract, è possibile dichiarare un contratto come “deceduto”. Si può dire alla blockchain che quel contratto, da un certo momento in poi, non deve essere più utilizzato e qualsiasi transazione diretta verso quel contratto dovrà essere considerata non valida: tutte le dApp che insistono su quel contratto non saranno più funzionanti e dovranno necessariamente aggiornare il proprio puntatore al contratto giusto.

Questo è un modo, se volete più brutale, per forzare la rete di qualsiasi applicazione che sta utilizzando lo smart contract senza sapere a priori quali siano queste applicazioni. Sembra che io mi contraddica, ma poter far suicidare un contratto deve ovviamente rientrare fra le regole del contratto stesso: infatti OpenZeppelin, ad esempio, realizza una classe di smart contract che è, appunto, “suicidabile”. Ma se dichiaro suicidabile un contratto con OpenZeppelin, questo avrà automaticamente tale funzionalità; una funzionalità base che tutti i contratti dovrebbero avere, in quanto in sua assenza quel contratto continuerà a vivere in maniera indefinita – magari contenendo al suo interno una vulnerabilità di sicurezza – e potranno esserci applicazioni che continuano a utilizzare il contratto fallato, con conseguenze imprevedibili e potenzialmente molto gravi.

Ulteriori aspetti di sicurezza riguardano la parte tradizionale della dApp di finanza decentralizzata, come appunto il back-end, la parte di API e la parte di front-end web o mobile: anch’essa fa parte della dApp di finanza decentralizzata e deve essere considerata quando si analizzano gli aspetti di sicurezza informatica.

Non c’è nulla di specifico e peculiare rispetto a qualsiasi altra applicazione web, quindi si utilizzano gli strumenti che normalmente vengono impiegati per analizzare e per rendere sicure le applicazioni web o le applicazioni mobili di tipo tradizionale.

L’unico elemento specifico delle dApp, ripeto, è la necessità di una gestione corretta da un punto di vista di interagibilità con l’utente, quindi l’aspetto di trust tra il wallet e l’applicazione web che realizza l’applicazione di dApp centralizzata.

L’ultimo aspetto che voglio trattare riguarda la confidenzialità. Le blockchain funzionano molto bene: la relativa visione, l’idea di una coreografia implementata da attori assolutamente paritari tra loro che realizzano un sistema assolutamente integro nelle regole che esso stesso definisce, è assolutamente e tecnicamente molto attraente. Tutto questo però ha un costo.

Tutte le blockchain di tipo mainstream di cui abbiamo conoscenza – come Bitcoin, Ethereum e così via – in realtà richiedono che tutte le transazioni siano sempre osservabili da chiunque voglia utilizzare la blockchain. Quindi, se si utilizza una blockchain e ci si vuole fidare di essa, si deve poter osservare tutto quello che succede al suo interno; e se ci sono transazioni che viaggiano all’interno della blockchain bisogna poterle osservare, in conflitto con la confidenzialità.

Questo è un aspetto sostanzialmente diverso rispetto ad applicazioni tradizionali che gestiscono altri aspetti finanziari della nostra vita. La mia banca non dovrà dire a chiunque qual è il saldo del mio conto, quali transazioni io faccio sul mio conto corrente: semplicemente non è richiesto. Nella blockchain, invece, questo è un elemento presente.

Esistono alcune blockchain che in qualche maniera hanno implementato meccanismi che preservano la confidenzialità delle transazioni, perché in realtà quello che è richiesto dalla blockchain è che consenta non tanto di poter osservare le transazioni, ma di avere la garanzia che esse siano conformi ai contratti definiti dagli smart contract.

Quindi, ad esempio, si può ottenere una transazione cifrata su cui avere la garanzia del contenuto, pur non conoscendo il contenuto della trattazione: così come nel caso di un bonifico non conosco chi effettua il bonifico né la quantità di denaro movimentata, però ho la garanzia che la persona che ha inviato quel denaro avesse un saldo che gli consentiva di trasferire quella determinata quantità di denaro. Questa è l’unica informazione a mia disposizione; e se, pur non avendo visibilità totale delle transazioni, si ha questa garanzia, la blockchain continua a funzionare. Questo è un tipo diverso di blockchain.

Le due principali sono Monero – che però non è utile per applicazioni di finanza decentralizzata perché è una specie di Bitcoin ma con transazioni confidenziali, quindi realizza una specifica applicazione finanziaria di trasferimento di liquidità – e Zcash, che implementa un vero e proprio meccanismo di smart contract totalmente confidenziali, dove si ha la garanzia che le transazioni siano conformi alle regole definite.

Ethereum, la principale piattaforma di realizzazione di applicazioni di finanza decentralizzata, contiene già al proprio interno le tecnologie che sono utilizzate da Zcash, che è stato precursore rispetto a questo tipo di applicazioni non solo ad alta integrità, ma ad alta confidenzialità.

La stessa tecnologia utilizzata da Zcash, le zero knowledge proof, è attualmente presente all’interno di Ethereum e può già essere utilizzata per incrementare parti confidenziali di uno smart contract. Una realtà che già esiste, quindi; e che va tenuta in considerazione quando si realizzano applicazioni di finanza decentralizzata.

Riassumendo: abbiamo parlato di smart contract, di dApp che realizzano applicazioni di finanza decentralizzata e abbiamo velocemente osservato i principali aspetti di sicurezza di questo tipo di applicazioni. Spero di essere stato esaustivo!

Il contenuto è tratto dal mio intervento al Cyber Security Virtual Conference di cui è disponibile il video completo.

 

A cura di Cristiano Paris, Consigliere di AIEA – Capitolo di Milano di ISACA

Profilo Autore

Cristiano Paris si è laureato con lode nel 2002 in Ingegneria Informatica presso l’Università di Roma “Tor Vergata”. Dal 2004 al 2007 dirige il laboratorio di innovazione e ricerca di Land S.r.l. dove sviluppa un innovativo algoritmo per l’utilizzo di tecnologie di firma digitale per autenticare documenti cartacei, brevettato in Italia. Successivamente, dal 2007 al 2016 è IT Auditor presso il Servizio Revisione interna di Banca d’Italia. Dal 2016 è in distacco temporaneo presso la Banca Centrale Europea e attualmente ricopre il ruolo di Senior Cyber Security Expert presso il Direttorato Infrastrutture finanziarie e sistemi di pagamento. Dal 2019 è membro del consiglio direttivo di AIEA, capitolo di Milano di ISACA, dove si occupa di innovazione.

Condividi sui Social Network:

Articoli simili