# Entérate profundamente sobre el ataque de Reentrancy y formas efectivas de prevenirlo

## ¿Qué es el ataque de Reentrancy?

El ataque de Reentrancy es una vulnerabilidad crítica en contratos inteligentes donde una función puede ser llamada repetidamente antes de que se complete su ejecución inicial. Esto permite a un atacante extraer fondos múltiples veces de un contrato.

## Cómo funciona el ataque

1. **Primera llamada**: El atacante invoca una función de retiro del contrato víctima
2. **Llamada recursiva**: Durante la ejecución, el contrato víctima envía fondos al atacante
3. **Fallback malicioso**: El atacante utiliza una función fallback para llamar nuevamente a la función de retiro
4. **Repetición**: El proceso se repite antes de que se actualice el saldo

## Ejemplo clásico: The DAO

El ataque de 2016 al DAO fue causado por esta vulnerabilidad, resultando en la pérdida de ~$50 millones en Ether.

## Métodos efectivos de prevención

### 1. Patrón Checks-Effects-Interactions (CEI)
- Verificar condiciones primero
- Actualizar estados del contrato
- Interactuar con contratos externos al final

### 2. Mutex o Lock (Reentrancy Guard)
```
nonReentrant modifier que previene llamadas recursivas
```

### 3. Estado de cambio antes de transferencias
- Decrementar saldo antes de enviar fondos
- Evitar que el atacante vuelva a retirar

### 4. Usar OpenZeppelin ReentrancyGuard
- Librería audida y confiable
- Implementación simple y segura

## Mejores prácticas

- Realizar auditorías de seguridad
- Usar herramientas como Slither y Mythril
- Testear exhaustivamente todos los escenarios
- Mantener contratos simples y legibles

La prevención de Reentrancy es esencial para la seguridad de cualquier protocolo DeFi.

El ataque de reentrancy es una de las amenazas de seguridad más graves para los contratos inteligentes. Este artículo te guiará no solo sobre cómo funciona la reentrancy, sino también sobre cómo proteger tu proyecto de manera integral.

Para tener una visión completa, comenzaremos con los conceptos básicos, luego analizaremos el código fuente de ataques reales y, por último, exploraremos tres técnicas de protección comprobadas: desde el modificador nonReentrant() hasta GlobalReentrancyGuard() y el patrón de chequeo-efecto-interacción.

¿Qué tipo de ataque es la reentrancy?

Imagina dos contratos inteligentes interactuando entre sí. ContractA y ContractB pueden llamarse mutuamente. Esto parece normal, pero es precisamente la vulnerabilidad que un atacante puede explotar.

El concepto central de reentrancy es: un contrato inteligente puede llamar a otro contrato y, mientras este aún está en ejecución, volver a llamar a ese mismo contrato o a otro. Esto puede crear un ciclo infinito si no se controla adecuadamente.

Para ilustrarlo, considera la siguiente situación: ContractA tiene 10 Ether, y ContractB ha enviado 1 Ether a él. Normalmente, cuando ContractB solicita retirar fondos, se verifica (saldo > 0), se envía Ether y luego se pone el saldo a cero. Pero con reentrancy, este proceso puede repetirse varias veces antes de que se actualice el saldo.

Cómo funciona un ataque de Reentrancy

El atacante necesita dos componentes principales: una función attack() y una función fallback().

La función fallback es una función especial en Solidity — una función externa sin nombre, sin parámetros y sin valor de retorno. Se activa automáticamente cuando:

  • Se llama a una función que no existe en el contrato
  • Se envía datos sin especificar función
  • Se transfiere Ether sin datos

Veamos cómo se desarrolla el ataque paso a paso:

Paso 1: El atacante llama a attack(), que a su vez llama a la función de retiro en ContractA.

Paso 2: ContractA verifica si el saldo del atacante es mayor que cero. Como es así, envía 1 Ether y activa la función fallback.

Paso 3: Aquí está el punto clave: aún no se ha actualizado el saldo a cero. ContractA sigue ejecutando la función de retiro.

Paso 4: La función fallback se activa y llama de inmediato a la función de retiro en ContractA.

Paso 5: ContractA vuelve a verificar: el saldo del atacante todavía es mayor que cero (porque no se actualizó). Envía otro Ether y vuelve a activar fallback.

Este ciclo se repite hasta que ContractA se quede sin Ether. Por eso, la reentrancy es tan peligrosa.

Análisis del código del ataque

Para entender mejor, veamos un ejemplo con un contrato EtherStore. Este contrato tiene dos funciones principales:

  • deposit(): almacena y actualiza el saldo del remitente
  • withdrawAll(): retira todo el saldo de una vez

La función withdrawAll() realiza: verificar (saldo > 0), enviar Ether, y poner saldo a cero.

Aquí está la vulnerabilidad: el envío de Ether ocurre antes de actualizar el saldo, permitiendo que un atacante intercepte y repita la llamada.

El contrato Attack está diseñado para explotar esto. Tiene:

  • Un constructor que recibe la dirección de EtherStore
  • Una función fallback() que llama a withdrawAll() mientras tenga Ether
  • Una función attack() para iniciar el ataque

El proceso de ataque es simple:

  1. El atacante llama a attack() enviando Ether
  2. attack() deposita Ether en EtherStore para que el saldo sea > 0
  3. attack() llama a withdrawAll() en EtherStore
  4. EtherStore envía Ether → activa fallback de Attack
  5. fallback llama a withdrawAll() otra vez, antes de que se actualice el saldo
  6. Este ciclo continúa hasta que EtherStore se quede sin Ether

Tres técnicas para prevenir ataques de Reentrancy

Técnica 1: Usar el modificador nonReentrant

La forma más sencilla de proteger una función específica es usar el modificador nonReentrant. Los modificadores en Solidity permiten agregar condiciones o funciones adicionales a otras funciones sin repetir toda la lógica.

Cómo funciona nonReentrant:

  • Bloquea el contrato al comenzar la función
  • Cualquier llamada recursiva será rechazada
  • Solo cuando la función termina, se desbloquea

Desventaja: solo protege una función a la vez, no evita reentrancy cruzadas entre funciones diferentes.

Técnica 2: Patrón Check-Effect-Interaction

Es una forma más avanzada de proteger múltiples funciones. En lugar de bloquear el contrato, cambias el orden de ejecución del código.

Este patrón requiere:

  • Check (Verificación): verificar todas las condiciones antes (require)
  • Effect (Efecto): actualizar todos los estados inmediatamente
  • Interaction (Interacción): solo al final llamar a contratos externos o enviar Ether

Comparando código vulnerable y seguro:

  • Vulnerable: Check → Enviar Ether → Actualizar saldo (el fallo está entre enviar y actualizar)
  • Seguro: Check → Actualizar saldo → Enviar Ether

Al actualizar el saldo justo después de la verificación, incluso si hay una llamada recursiva, el saldo ya está actualizado, neutralizando el ataque.

Técnica 3: GlobalReentrancyGuard para múltiples contratos

Esta técnica es para proyectos con varios contratos que interactúan. La idea es crear un contrato central que controle la reentrancy en todo el sistema.

En lugar de que cada contrato tenga su propia variable de bloqueo, todos referencian a un GlobalReentrancyGuard. Esto permite:

  • Controlar la reentrancy entre diferentes contratos
  • Evitar ataques de cadena complejos

Por ejemplo, si ScheduledTransfer envía Ether a AttackTransfer, y AttackTransfer intenta llamar a otros contratos, el guardia global puede detectar y bloquear esto.

Cómo elegir la técnica adecuada

Usar nonReentrant cuando:

  • Solo necesitas proteger una o pocas funciones
  • El costo adicional no es un problema
  • No te preocupa la reentrancy entre funciones

Usar Check-Effect-Interaction cuando:

  • Quieres optimizar el gas
  • Tienes muchas funciones que proteger
  • Quieres seguir buenas prácticas en todo el proyecto

Usar GlobalReentrancyGuard cuando:

  • Tu sistema de contratos es complejo
  • Hay interacción frecuente entre contratos
  • Necesitas una protección centralizada y uniforme

Lo ideal es combinar las tres técnicas según las necesidades específicas de tu proyecto.

Conclusión

Los ataques de reentrancy no son imposibles de prevenir, siempre que entiendas cómo funcionan y apliques las técnicas correctas. Desde el simple modificador nonReentrant hasta el completo GlobalReentrancyGuard, cada herramienta tiene su papel en la seguridad de los contratos inteligentes.

Recuerda que la seguridad no es opcional, sino una obligación. Comprender estos ataques y aplicar las defensas adecuadas te permitirá construir contratos seguros y eficientes.

Para más información sobre seguridad en Web3, Solidity, auditoría de contratos y temas relacionados, sigue a @TheBlockChainer en Twitter.

Ver originales
Esta página puede contener contenido de terceros, que se proporciona únicamente con fines informativos (sin garantías ni declaraciones) y no debe considerarse como un respaldo por parte de Gate a las opiniones expresadas ni como asesoramiento financiero o profesional. Consulte el Descargo de responsabilidad para obtener más detalles.
  • Recompensa
  • Comentar
  • Republicar
  • Compartir
Comentar
Añadir un comentario
Añadir un comentario
Sin comentarios
  • Anclado