
Seguridad de Solidity
Esta publicación pretende ser una introducción relativamente profunda y actualizada que detalla los errores pasados cometidos por desarrolladores de Solidity, con el fin de evitar que los futuros desarrolladores repitan la historia.
Una de las características de los contratos inteligentes de Ethereum es la capacidad de llamar y utilizar código de otros contratos externos. Los contratos también suelen manejar ether y, como tal, a menudo envían ether a diversas direcciones de usuarios externos. La operación de llamar a contratos externos, o enviar ether a una dirección, requiere que el contrato realice una llamada externa. Estas llamadas externas pueden ser secuestradas por atacantes, quienes fuerzan al contrato a ejecutar código adicional (es decir, a través de una función fallback) , incluidas llamadas de vuelta a sí mismo. Así, la ejecución del código "re-entra" en el contrato. Ataques de este tipo se utilizaron en el infame hackeo de The DAO.
Para más información sobre ataques de reentrancia, consulte Ataque de Reentrancia en Contratos Inteligentes y Consensus - Mejores Prácticas para Contratos Inteligentes de Ethereum.
Este ataque puede ocurrir cuando un contrato envía ether a una dirección desconocida. Un atacante puede construir cuidadosamente un contrato en una dirección externa que contenga código malicioso en la función fallback. Por lo tanto, cuando un contrato envía ether a esta dirección, invocará el código malicioso. Típicamente, el código malicioso ejecuta una función en el contrato vulnerable, realizando operaciones no esperadas por el desarrollador. El nombre "reentrancia" proviene del hecho de que el contrato malicioso externo llama de vuelta a una función en el contrato vulnerable y "re-entra" en la ejecución del código en una ubicación arbitraria del contrato vulnerable.
Para aclarar esto, considere el siguiente contrato vulnerable, que actúa como una bóveda de Ethereum que permite a los depositantes retirar solo 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;
}