Abbiamo appena visto come una piccola scappatoia porta a una perdita finanziaria (di varia entità), allo stesso modo in cui i contratti intelligenti sviluppati su Solidity sono soggetti a vari attacchi noti e sconosciuti. Gli sfruttatori sfruttano i bug e le scappatoie per sbirciare nei contratti intelligenti e manipolarli per eseguire attacchi. Qui presentiamo un elenco completo dei primi 5 errori comunemente riscontrati nel linguaggio di programmazione Solidity.
In QuillAudits seguiamo la metodologia adattiva per ottenere il succo di ogni hack e implementare i suoi apprendimenti sui futuri contratti intelligenti per evitare qualsiasi potenziale minaccia.
Errori nel linguaggio di programmazione della solidità
1. Chiamata esterna non selezionata
Stiamo tirando fuori questo problema in primo luogo perché è una delle insidie più comunemente osservate di Solidity. Generalmente, l'invio di ether a qualsiasi account esterno viene effettuato tramite il trasferimento() funzione. A parte questo, le due funzioni più utilizzate per effettuare una chiamata esterna sono; chiamata()e send (), qui principalmente il chiamata() La funzione è ampiamente utilizzata per eseguire chiamate esterne versatili dagli sviluppatori.
Anche se la chiamata() ed send () le funzioni restituiscono un valore booleano che specifica se la chiamata ha avuto successo o meno. Quindi in questo caso, se una qualsiasi delle funzioni chiamata() or send () non riesce a eseguire l'attività, verranno ripristinati con a falsa. Quindi, se lo sviluppatore non esegue un controllo incrociato del valore restituito, diventerebbe una trappola.
La vulnerabilità
Considera l'esempio seguente:
contratto Lotto{
boolpublic paidOut =false;
indirizzo pubblico vincitore;
importo winintpublic;
// … funzionalità extra qui
funzione sendToWinner()public{
require(!pagato);
vincitore.send(winAmount);
pagatoOut =vero;
}
funzione ritiraLeftOver()public{
richiedere (pagato);
msg.sender.send(this.balance);
}
}
Nel contratto tipo Lotto sopra, possiamo osservare che a vincitore riceve importovincita di etere lasciando un piccolo avanzo da prelevare da qualsiasi agente esterno.
Qui, l'insidia per il contratto esiste alla riga [11], dove a inviare viene utilizzato senza convalida incrociata della risposta. Nell'esempio sopra, a vincitore la cui transazione fallisce (o per carenza di Gas o se si tratta di un contratto che intenzionalmente getta la funzione di fallback), autorizza pagato essere impostato su vero indipendentemente dal fatto che la transazione dell'etere sia stata un successo o meno. In questo caso, qualsiasi sfruttatore può ritirare il del vincitore vincite tramite il ritiraLeftOver funzione.
L'approccio di QuillAudit
Il nostro team interno di sviluppatori affronta questo bug con l'uso di [trasferimento] funzione invece di [Spedire] funzione, poiché [trasferimento] verrà ripristinato se la transazione esterna viene ripristinata. E se stai usando [invia], controlla sempre il valore restituito.
Uno degli approcci robusti che seguiamo è l'utilizzo di un [modello di prelievo]. Qui isoliamo logicamente la funzionalità di invio esterno dal resto della base di codice e poniamo il carico di transazioni potenzialmente fallite sull'utente finale, poiché è lui a chiamare la funzione di prelievo.
2. Rientro
Gli smart contract Ethereum chiamano e utilizzano codici di altri contratti esterni e, per farlo, i contratti devono inviare chiamate esterne. Queste chiamate esterne sono vulnerabili e soggette ad attacchi, uno di questi attacchi si è verificato di recente nel caso di hacking DAO.
La vulnerabilità
Gli aggressori effettuano tali attacchi quando un contratto invia ether a un indirizzo sconosciuto. In questo caso, l'attaccante può creare un contratto a un indirizzo esterno che possiede codice dannoso nella funzione di fallback e questo codice dannoso verrà invocato quando il contratto invia ether a questo indirizzo.
Fatto: Il termine "Rientro" è stato coniato dal fatto che quando un contratto dannoso esterno chiama una funzione sul contratto vulnerabile e quindi il percorso di esecuzione del codice lo "rientra".
Considera l'esempio seguente, è un caveau Ethereum che consente ai depositanti di prelevare solo 1 ether a settimana.
contratto EtherStore {
uint256 public prelievoLimit = 1 etere;
mapping(address => uint256) public lastWithdrawTime;
mapping(address => uint256) bilanci pubblici;
funzione depositFunds() debito esterno {
saldi[msg.sender] += msg.value;
}
funzione ritiraFunds (uint256 _weiToWithdraw) public {
require(saldi[msg.sender] >= _weiToWithdraw);
// limita il prelievo
require(_weiToWithdraw <= ritiroLimit);
// limita il tempo concesso per prelevare
require(now >= lastWithdrawTime[msg.sender] + 1 settimane);
require(msg.sender.call.value(_weiToWithdraw)());
saldi[msg.sender] -= _weiToWithdraw;
lastWithdrawTime[msg.sender] = ora;
}
}
Nel contratto di cui sopra, abbiamo due funzioni pubbliche, [depositFunds] e [withdrawFunds]. Il [depositFunds] viene utilizzato per incrementare il saldo del mittente, mentre [withdrawFunds] specifica l'importo da prelevare. In questo caso, sarà un successo se l'importo da prelevare è inferiore a 1 ether.
La trappola qui sta nella riga [17] in cui avviene il trasferimento dell'etere. L'autore dell'attacco potrebbe creare un contratto dannoso con l'indirizzo del contratto di [EtherStores] come unico parametro del costruttore. Ciò renderebbe [etherStore] una variabile pubblica, quindi più incline ad essere attaccata.
L'approccio di QuilllAudit
Seguiamo varie tecniche per evitare potenziali vulnerabilità di rientro negli smart contract. Il primo e il miglior modo possibile è l'uso della funzione [trasferimento] incorporata durante il trasferimento di ether a qualsiasi contratto esterno.
In secondo luogo, è importante garantire che tutte le modifiche logiche nelle variabili di stato vengano eseguite prima di inviare ether fuori dal contratto. Nell'esempio [EtherStore], le righe [18] e [19] devono essere messe prima della riga [17].
Una terza tecnica può essere utilizzata anche per prevenire le chiamate rientranti; attraverso l'introduzione di un mutex. È un'aggiunta di una variabile di stato che bloccherà il contratto durante l'esecuzione del codice.
3. Visibilità predefinite
Ci sono identificatori di visibilità per le funzioni che usiamo in Solidity e prescrivono il modo in cui possono essere chiamati. È la visibilità che determina l'invocazione delle funzioni; esternamente dagli utenti, da altri contratti derivati, solo internamente o solo esternamente. Diamo un'occhiata a come l'uso errato degli specificatori di visibilità può causare un'enorme vulnerabilità nei contratti intelligenti.
La vulnerabilità
Per impostazione predefinita, la visibilità della funzione è [pubblica], quindi gli utenti esterni possono chiamare le funzioni senza visibilità specifica. Il bug si verifica quando gli sviluppatori dimenticano di specificare la visibilità sulle funzioni che dovrebbero essere private (o che possono essere chiamate all'interno del contratto stesso). Per esempio;
contratto HashForEther {
function prelevaVincimenti() {
// Vincitore se gli ultimi 8 caratteri esadecimali dell'indirizzo sono 0
require(uint32(msg.sender) == 0);
_sendWinnings();
}
funzione _sendWinnings() {
msg.sender.transfer(this.balance);
}
}
Il contratto di cui sopra è un semplice gioco di taglie per indovinare l'indirizzo. In questo, possiamo vedere che la visibilità delle funzioni non è specificata, in particolare la funzione [ _sendWinnings] è [pubblica] (di default), quindi questa può essere chiamata tramite qualsiasi indirizzo per rubare la taglia.
L'approccio di QuillAudit
Il nostro team interno è composto da sviluppatori esperti che seguono sempre le migliori pratiche di audit, qui la visibilità delle funzioni dovrebbe essere specificata in modo esplicito, anche se devono essere mantenute pubbliche, dovrebbe essere menzionata.
4. Tutela dell'uso dei costruttori
Generalmente, i costruttori sono chiamati funzioni speciali che vengono utilizzate per eseguire attività critiche e privilegiate durante l'inizializzazione dei contratti. Prima di Solidity [v0.4.22], i costruttori avevano lo stesso nome utilizzato dal contratto che li conteneva. Ora, considera un caso in cui il nome del contratto viene modificato durante la fase di sviluppo ma il nome del costruttore rimane lo stesso, questa scappatoia può anche fornire agli aggressori un facile accesso al tuo contratto intelligente.
La vulnerabilità
Può portare a gravi conseguenze se il nome del contratto viene modificato ma il nome del costruttore rimane invariato. Per esempio:
contratto OwnerWallet {
indirizzo pubblico titolare;
// costruttore
funzione ownerWallet(indirizzo _proprietario) public {
proprietario = _proprietario;
}
// Ricaderci. Raccogliere l'etere.
funzione () pagabile {}
funzione ritira() public {
require(msg.sender == proprietario);
msg.sender.transfer(this.balance);
}
}
Nel contratto di cui sopra, possiamo vedere che solo il proprietario può prelevare ether chiamando la funzione [ritira]. Qui, la vulnerabilità si verifica quando il nome del costruttore è diverso dal contratto (la prima lettera è diversa!). Così lo sfruttatore può chiamare la funzione [ownerWallet] e autorizzarsi come proprietario, e quindi ritirare tutto l'etere in contratto chiamando [ritira].
L'approccio di QuillAudit
Rispettiamo la versione [0.4.22] del compilatore Solidity. Questa versione ha introdotto una parola chiave; [costruttore] che richiede che il nome della funzione corrisponda al nome del contratto.
5. Autenticazione Tx.Origin
Qui, [Tx.Origin] è la variabile globale di Solidity, contiene l'indirizzo dell'account che ha originariamente eseguito la chiamata o la transazione. Questa variabile non può essere utilizzata per l'autenticazione, in quanto ciò rende il contratto vulnerabile agli attacchi di phishing.
La vulnerabilità
I contratti che autorizzano gli utenti tramite la variabile [tx.origin] sono esposti ad attacchi esterni che portano gli utenti a eseguire azioni autenticate sul contratto errato. Considera l'esempio seguente:
contratto Phishable {
indirizzo pubblico titolare;
costruttore (indirizzo _proprietario) {
proprietario = _proprietario;
}
function() esterna pagabile {} // raccoglie etere
funzione ritiraTutto(indirizzo _destinatario) pubblico {
require(tx.origin == proprietario);
_destinatario.trasferimento(questo.saldo);
}
}
Qui alla riga [11], il contratto autorizza la funzione [withdrawAll] con l'aiuto di [tx.origin].
L'approccio di QuillAudit
In genere evitiamo di utilizzare [tx.origin] per l'autorizzazione nei contratti intelligenti. Sebbene l'uso di [tx.origin] non sia severamente proibito, ha alcuni casi d'uso specifici. Possiamo usare [tx.origin] per negare ai contratti esterni di chiamare il presente contratto, può essere eseguito con [require] nella forma [require(tx.origin == msg.sender)]. È fatto per evitare la chiamata di contratti intermedi per chiamare il contratto in corso che limita il contratto a normali indirizzi senza codice.
Conclusione finale
Abbiamo coperto in modo esauriente le cinque insidie comuni nel linguaggio Solidity. Durante lo sviluppo di contratti intelligenti, non dobbiamo dimenticare che sono immutabili per progettazione, il che significa che una volta creati, non c'è modo di correggere il codice sorgente.
Ciò rappresenta una grande sfida per gli sviluppatori per sfruttare i vantaggi dei test di sicurezza disponibili e degli strumenti di controllo prima della distribuzione.
La scoperta di potenziali minacce dannose ai contratti intelligenti e i rischi, alcuni dei quali abbiamo menzionato sopra, vengono eseguiti in un modo davvero unico e robusto dal nostro team interno di esperti di audit. Noi di QuillAudits mettiamo i nostri migliori sforzi nella ricerca sulla sicurezza per mantenere aggiornato il tuo contratto con tutte le pratiche di sicurezza del software per mantenere il tuo contratto sicuro e protetto.
Contatta QuillHash
Con una presenza nel settore di anni, QuillHash ha fornito soluzioni aziendali in tutto il mondo. QuillHash con un team di esperti è una società leader nello sviluppo di blockchain che fornisce varie soluzioni di settore tra cui l'impresa DeFi, se hai bisogno di assistenza per l'audit dei contratti intelligenti, sentiti libero di contattare i nostri esperti qui!
Segui QuillHash per ulteriori aggiornamenti
Fonte: https://blog.quillhash.com/2021/06/04/top-5-common-errors-in-solidity-programming-language/
- 11
- Il mio account
- Vantaggio
- Tutti
- revisione
- Autenticazione
- autorizzazione
- MIGLIORE
- blockchain
- Insetto
- bug
- chiamata
- casi
- Causare
- Challenge
- codice
- Uncommon
- azienda
- contratto
- contratti
- Corrente
- DAO
- DeFi
- Design
- Costruttori
- sviluppatori
- Mercato
- Impresa
- etere
- Ethereum
- Evento
- esperti
- finanziario
- Nome
- seguire
- modulo
- Gratis
- function
- futuro
- gioco
- GAS
- globali
- grande
- incidere
- qui
- Come
- HTTPS
- Enorme
- Compreso
- industria
- IT
- Lingua
- portare
- principale
- linea
- Lista
- partita
- Altro
- proprietario
- Toppa
- Cartamodello
- phishing
- attacchi di phishing
- prescrivere
- presenti
- un bagno
- Programmazione
- la percezione
- traino
- riparazioni
- risposta
- REST
- sicura
- problemi di
- Servizi
- set
- Un'espansione
- piccole
- smart
- smart contract
- Smart Contract
- So
- Software
- solidità
- Soluzioni
- Regione / Stato
- il successo
- Testing
- L’ORIGINE
- minacce
- tempo
- top
- top 5
- delle transazioni
- Le transazioni
- us
- utenti
- APPREZZIAMO
- Volta
- visibilità
- vulnerabilità
- vulnerabilità
- Vulnerabile
- settimana
- OMS
- entro
- anni