
Segurança Solidity
Este post pretende ser um post introdutório relativamente aprofundado e atualizado, detalhando os erros passados que foram cometidos por desenvolvedores Solidity, num esforço para evitar que futuros devs repitam a história.
Uma das características dos contratos inteligentes Ethereum é a capacidade de chamar e utilizar código de outros contratos externos. Os contratos também normalmente lidam com ether e, como tal, frequentemente enviam ether para vários endereços de utilizadores externos. A operação de chamar contratos externos, ou enviar ether para um endereço, exige que o contrato submeta uma chamada externa. Estas chamadas externas podem ser sequestradas por atacantes, que forçam o contrato a executar código adicional (ou seja, através de uma função fallback) , incluindo chamadas de volta para ele mesmo. Assim, a execução de código "re-entra" no contrato. Ataques desse tipo foram usados no infame hack da DAO.
Para leitura adicional sobre ataques de reentrância, consulte Ataque de Reentrância em Contratos Inteligentes e Consensus - Melhores Práticas para Contratos Inteligentes Ethereum.
Este ataque pode ocorrer quando um contrato envia ether para um endereço desconhecido. Um atacante pode construir cuidadosamente um contrato num endereço externo que contém código malicioso na função fallback. Assim, quando um contrato envia ether para este endereço, o código malicioso será invocado. Normalmente, o código malicioso executa uma função no contrato vulnerável, realizando operações não esperadas pelo desenvolvedor. O nome "reentrância" vem do facto de o contrato malicioso externo chamar de volta uma função no contrato vulnerável e "re-entrar" na execução de código num local arbitrário do contrato vulnerável.
Para clarificar isto, considere o simples contrato vulnerável, que atua como um cofre Ethereum que permite aos depositantes retirar apenas 1 ether por semana.
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;
}