Considerazioni e attacchi sulla sicurezza del prestito flash
Di cosa devono essere consapevoli gli sviluppatori per proteggere i propri contratti e sistemi dai prestiti flash?
A cosa devono pensare e da cosa proteggersi?
Risposte
Mentre lavoriamo sui debriefing degli attacchi di prestito flash , possiamo raccogliere molte informazioni su ciò che avrebbe potuto essere preso come misura preventiva. È importante capire come funzionano questi prestiti flash prima di approfondire le cause profonde e l'analisi.
I prestiti flash sono prestiti concessi senza garanzie e restituiti nella stessa transazione in cui sono stati prestati. Questo è possibile nel mondo degli smart contract, perché il codice può verificare se potrà o meno restituire il prestito alla fine del blocco. In caso affermativo, è in grado di prestare quanto l'utente ha bisogno. È qui che entrano in gioco i vettori di attacco.
Possiamo attingere da uno studio condotto da accademici dell'Imperial College di Londra che esamina in particolare due famigerati attacchi. La loro scoperta principale è la seguente:
Gli attacchi di prestito flash sono generalmente attacchi Oracle Price / Oracle Manipulation
Questa sembra essere di gran lunga la prima causa di attacchi al momento. Ciò che è importante notare è che gli scambi decentralizzati non sono oracoli decentralizzati . L'utilizzo di Uniswap, Sushiswap o Curve per ottenere informazioni sui prezzi per eseguire operazioni sta estraendo dati da potocols il cui prezzo dipende esclusivamente dalla liquidità. Guardando il famigerato attacco bZx ground zero che ha scatenato questa ondata di attacchi, possiamo vedere esattamente cosa succede. Questi prestiti flash vengono utilizzati per bloccare e manipolare il prezzo di questi scambi decentralizzati, che la maggior parte dei progetti considera sicuri da usare. Il problema qui si basa sul fatto che i prezzi di questi protocolli dipendono interamente dalla liquidità. Ecco fondamentalmente come funziona:
- L'utente prende un enorme prestito
- L'utente utilizza quel prestito per acquistare tutta la liquidità su un lato di un pool di liquidità, provocando un enorme calo del prezzo
- Questo prezzo viene utilizzato da un altro protocollo per determinare o eseguire un codice, ovvero, legano il prezzo della loro risorsa all'asset del protocollo. Quindi l'utente scambia per quasi nulla per un enorme profitto.
- Quindi rimborsa il prestito originale e se ne va con enormi guadagni
Ciò che i revisori e gli ingegneri del software devono fare è assicurarsi di non ottenere prezzi o dati che si basano su DEX. Uniswap è uno scambio decentralizzato NON un oracolo di prezzi decentralizzato, sono ciascuno un punto dati centralizzato e utilizzarli come tali è pericoloso al punto in cui negli ultimi 2 mesi, ~ 5 protocolli sono stati violati per oltre $ 30 milioni combinati.
Prevenzione
Detto questo, per evitare che questi attacchi si verifichino, devi assicurarti che quando ricevi informazioni sui prezzi, o qualsiasi dato, deve provenire da oracoli decentralizzati e ottenere i dati da feed di prezzo Chainlink decentralizzati , se sono dati sui prezzi. Per qualsiasi altro dato è necessario ottenere i dati da una rete decentralizzata di Chainlink Oracles . E come ingegnere, chiunque può personalizzare la propria rete Oracle per renderla ampia o stretta a proprio piacimento.
Detto questo, a questo punto, ci sono abbastanza informazioni là fuori che se un protocollo viene violato e quel protocollo ha pagato un revisore, anche quel revisore deve essere ritenuto responsabile, poiché la mancanza di oracoli di prezzo centralizzati nelle revisioni di revisione questo continua a succedere. Molti progetti che sono stati violati hanno integrato i feed dei prezzi di Chainlink come spina dorsale per l'affidabilità dei dati e da allora si sono stabilizzati.
Il secondo attacco più popolare sono gli attacchi di rientro
Per citare:
Un attacco di rientranza può verificarsi quando si crea una funzione che effettua una chiamata esterna a un altro contratto non attendibile prima che risolva qualsiasi effetto. Se l'aggressore può controllare il contratto non attendibile, può effettuare una chiamata ricorsiva alla funzione originale, ripetendo interazioni che altrimenti non sarebbero state eseguite dopo che gli effetti sono stati risolti.
Fortunatamente, sappiamo che le funzioni di fallback sono state patchate per utilizzare solo 2300 gas, quindi questo può essere utile qui. Consensys consiglia di utilizzare alcall posto di transfero sendper proteggersi da questi.
Penso che questo sia un errore, penso che il trasferimento sia effettivamente più sicuro, e purché tu lavori tutto prima di effettuare una chiamata esterna, cioè prendi qualcosa come:
func withdraw() public {
token.transfer(to_address, amount);
balance = 0;
}
e modificalo in:
func withdraw() public {
balance = 0;
token.transfer(to_address, amount);
}
Altre note
Va detto che ci sono alcuni "hack" che risolveranno anche questo problema. Fare in modo che tutte le tue transazioni importanti avvengano nel corso di 2 o più blocchi può essere un modo hacker per aggirare alcuni di questi problemi. Inoltre vorrai sempre usarlo safeMathquando lavori con numeri interi enormi e devi assicurarti che i tuoi overflow non violino il tuo protocollo. Nota: sono CEO di Alpha Chain e Chainlink DevRel
I prestiti flash violano due comuni presupposti intuitivi.
1. "Nessuno ha così tanto ETH"
Possono sorgere problemi, ad esempio, quando:
- Il tuo contratto utilizza una formula non lineare con un importo ETH come parametro
- Il tuo contratto si basa sul fatto che nessuno abbia più di una certa quantità di ETH per evitare l'overflow di numeri interi
2. Il saldo di un indirizzo (e ETH ricevuto da un indirizzo) è di proprietà di quell'indirizzo
Possono sorgere problemi, ad esempio, quando:
- Il tuo contratto verifica se un indirizzo ha un saldo minimo controllando semplicemente il suo saldo corrente
- Il tuo contratto verifica se un indirizzo ha un saldo minimo ricevendo tale saldo minimo e rinviandolo nella stessa transazione
- Il tuo contratto ha un flusso di controllo basato sull'importo ETH (ad esempio, offrendo uno sconto per grandi acquisti di token e offrendo rimborsi parziali in modo che un prestito flash possa essere rimborsato)
In generale, se il sistema fornisce agli utenti termini diversi in scenari diversi, è necessario ricordare che un utente può eseguire un attacco di caricamento flash su di esso.
Ad esempio, se il tuo pool offre agli utenti un tasso di conversione migliore quando il pool è più profondo (saldi di riserva più alti), un utente può attaccarlo eseguendo atomicamente:
- Aggiungi liquidità e aumenta la profondità del pool
- Effettua una conversione da una riserva all'altra
- Rimuovere la liquidità e diminuire la profondità del pool
Questo tipo di attacco può drenare gradualmente (o anche improvvisamente) la tua piscina.
AGGIORNARE:
L'esempio sopra è realizzabile solo se all'utente è garantito di ricevere nell'ultima fase la stessa liquidità (importi di riserva) investita nella prima fase, indipendentemente dallo stato (saldi di riserva) del pool.
Questa restrizione non è garantita nella maggior parte dei pool attualmente in uso, rendendo inutile l'attacco di prestito flash illustrato in queste circostanze.
Le funzioni che possono essere giocate tramite prestiti flash dovrebbero impedire ai contratti intelligenti di interagire con quella specifica funzione come questa:
assert tx.origin == msg.sender, "No smart contract allowed"
Questa soluzione, pur limitando, è in realtà molto meno limitante rispetto al dover fare affidamento su oracoli esterni per tutti i dati.