
Sicurezza di Solidity
Questo post si propone di essere un post introduttivo relativamente approfondito e aggiornato che descrive gli errori passati commessi dagli sviluppatori di Solidity, nel tentativo di impedire ai futuri sviluppatori di ripetere la storia.
Una delle caratteristiche degli smart contract di Ethereum è la capacità di chiamare e utilizzare codice di altri contratti esterni. I contratti inoltre gestiscono tipicamente ether e, come tali, inviano spesso ether a vari indirizzi utente esterni. L'operazione di chiamare contratti esterni, o di inviare ether a un indirizzo, richiede che il contratto effettui una chiamata esterna. Queste chiamate esterne possono essere dirottate dagli attaccanti, i quali costringono il contratto a eseguire ulteriore codice (ad esempio tramite una funzione fallback), incluse chiamate di ritorno verso se stesso. L'esecuzione del codice "ri-entra" così nel contratto. Attacchi di questo tipo sono stati utilizzati nel famigerato hack di The DAO.
Per ulteriori letture sugli attacchi di re-entrancy, vedi Reentrancy Attack On Smart Contracts e Consensus - Ethereum Smart Contract Best Practices.
Questo attacco può verificarsi quando un contratto invia ether a un indirizzo sconosciuto. Un attaccante può costruire con cura un contratto a un indirizzo esterno che contenga codice dannoso nella funzione fallback. Pertanto, quando un contratto invia ether a questo indirizzo, verrà invocato il codice dannoso. In genere il codice dannoso esegue una funzione sul contratto vulnerabile, compiendo operazioni non previste dallo sviluppatore. Il nome "re-entrancy" deriva dal fatto che il contratto esterno dannoso richiama una funzione sul contratto vulnerabile e "ri-entra" nell'esecuzione del codice in un punto arbitrario del contratto vulnerabile.
Per chiarire questo concetto, si consideri il semplice contratto vulnerabile, che funge da caveau Ethereum e consente ai depositanti di prelevare solo 1 ether a settimana.
EtherStore.sol:```solidity contract EtherStore {
uint256 public withdrawalLimit = 1 ether;
mapping(address => uint256) public lastWithdrawTime;
mapping(address => uint256) public balances;
function depositFunds() public payable {
balances[msg.sender] += msg.value;
}