Solo quiero compartir un problema de seguridad en contratos inteligentes que muchos desarrolladores todavía suelen pasar por alto: el ataque de reentrancy. Si estás desarrollando contratos inteligentes en Solidity, esto es algo que debes entender a fondo.



De manera sencilla, reentrancy ocurre cuando un contrato llama a otro contrato, y ese contrato puede volver a llamar al contrato original mientras aún se está ejecutando. Imagina que tienes ContractA con 10 Ether y ContractB envía 1 Ether a ese contrato. Cuando ContractB retira dinero, ContractA verifica si el saldo es mayor que 0, y si lo es, envía Ether de vuelta. Sin embargo, si ContractB tiene una función fallback(, puede llamar de nuevo a la función de retiro de ContractA mientras esta aún no ha terminado. ¿El resultado? El saldo de ContractB sigue registrado como 1 Ether, por lo que recibirá otro Ether, y así sucesivamente hasta que ContractA se quede sin fondos.

¿Cómo funciona este tipo de ataque? El atacante necesita dos cosas: una función attack) para comenzar, y una función fallback para volver a llamar a la función de retiro. La función fallback es una función externa especial sin nombre, sin parámetros, que cualquiera puede activar llamando a una función inexistente, enviando Ether sin datos, o simplemente enviando Ether sin datos.

Un ejemplo concreto: el contrato EtherStore tiene una función deposit( que almacena el saldo y una función withdrawAll) que retira todo. El problema es que withdrawAll( verifica el saldo, envía Ether, y solo después actualiza el saldo a 0. Esto deja un espacio para que ocurra un ataque de reentrancy.

¿Y cómo protegerse? Aquí te doy tres formas.

Primero, usar el modificador noReentrant. La idea es muy simple: bloquear el contrato mientras una función se está ejecutando. Si alguien intenta volver a llamar esa función, debe pasar la verificación del bloqueo, pero el bloqueo solo se libera después de que la función termina. El modificador es una función especial que te permite agregar condiciones a otras funciones sin reescribir toda la lógica.

Segundo, aplicar el patrón Check-Effect-Interaction. En lugar de verificar condiciones, enviar fondos y luego actualizar el saldo, debes verificar primero, actualizar el saldo inmediatamente)antes de enviar fondos(, y luego realizar la interacción externa. De esta forma, incluso si ocurre reentrancy, el saldo ya estará actualizado a 0, y el atacante no podrá retirar más.

Tercero, si tu proyecto involucra múltiples contratos que interactúan, necesitas GlobalReentrancyGuard. En lugar de bloquear solo una función, bloqueas todo el sistema con una variable de estado almacenada en un contrato separado. Cuando cualquier función en cualquier contrato se llama, verifica si el sistema está bloqueado. Si lo está, la transacción se rechaza. Esto es especialmente útil si tienes contratos como ScheduledTransfer que envían dinero a AttackTransfer: GlobalReentrancyGuard evitará que toda la cadena de ataques de reentrancy ocurra.

Lo interesante de estos tres métodos es que puedes combinarlos según la situación. ¿Una función importante? Usa noReentrant. ¿Varias funciones relacionadas? Usa Check-Effect-Interaction. ¿Un proyecto completo y complejo? Usa GlobalReentrancyGuard. Entender reentrancy y cómo prevenirla te ayudará a construir contratos inteligentes mucho más seguros.
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