Logo
RPC Assistant

Prácticas recomendadas de seguridad en contratos inteligentes: lista de verificación para desarrolladores

Resumen

Aprende las prácticas esenciales de seguridad para contratos inteligentes en Solidity, incluyendo guardas de reentrancia, control de acceso y matemáticas seguras. Descubre cómo las elecciones de infraestructura, como puntos finales RPC confiables, respaldan despliegues y monitoreo seguros.

Lista de verificación de decisiones de seguridad para contratos inteligentes

Antes de desplegar cualquier contrato inteligente, verifica estos seis controles de seguridad:

  • Usa una guarda de reentrancia (por ejemplo, ReentrancyGuard de OpenZeppelin).
  • Aplica el patrón de verificaciones-efectos-interacciones.
  • Usa msg.sender para autenticación en lugar de tx.origin.
  • Usa modificadores de visibilidad explícitos (public, private, internal, external).
  • Maneja desbordamientos de enteros usando las comprobaciones incorporadas de Solidity 0.8+ o SafeMath para versiones anteriores.
  • Prueba en una testnet pública usando un punto final RPC confiable (por ejemplo, Sepolia a través de un proveedor como OnFinality) para simular condiciones reales.

Vulnerabilidades comunes en contratos inteligentes

Los contratos inteligentes ejecutan lógica en cadena que es inmutable después del despliegue. Esta inmutabilidad hace que la seguridad sea primordial. La siguiente tabla describe las vulnerabilidades más frecuentes y sus mitigaciones.

VulnerabilidadMitigaciónPor qué es importante
ReentranciaUsar guardas de reentrancia y el patrón de verificaciones-efectos-interaccionesEvita que atacantes llamen recursivamente una función de retiro para drenar fondos
Control de accesoImplementar acceso basado en roles (por ejemplo, AccessControl de OpenZeppelin)Asegura que solo actores autorizados puedan ejecutar funciones privilegiadas
Desbordamiento/subdesbordamiento de enterosUsar Solidity 0.8+ (comprobaciones incorporadas) o la librería SafeMathPreviene errores matemáticos que pueden llevar a acuñar tokens ilimitados o robar fondos
Llamadas externas sin verificarValidar valores de retorno de call / delegatecallEvita asumir que una llamada tuvo éxito cuando en realidad revirtió
Dependencia de timestampEvitar usar block.timestamp para lógica críticaLos mineros pueden manipular timestamps dentro de una pequeña ventana, rompiendo condiciones basadas en tiempo
Front-runningUsar esquemas de compromiso-revelación o colocar bloqueos de tiempoProtege a los usuarios de ver transacciones pendientes y explotar diferencias de precio

Prácticas recomendadas de seguridad en Solidity

1. Usar guardas de reentrancia

La reentrancia ocurre cuando un contrato realiza una llamada externa a un contrato no confiable antes de actualizar su propio estado. La función fallback del atacante puede reingresar a la función original y drenar fondos.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/security/ReentrancyGuard.sol";

contract SecureVault is ReentrancyGuard {
    mapping(address => uint256) public balances;

    function withdraw(uint256 _amount) external nonReentrant {
        require(balances[msg.sender] >= _amount, "Saldo insuficiente");
        balances[msg.sender] -= _amount;
        (bool success, ) = msg.sender.call{value: _amount}("");
        require(success, "Transferencia fallida");
    }
}

El modificador nonReentrant previene llamadas anidadas. Siempre actualiza el estado antes de hacer llamadas externas (verificaciones-efectos-interacciones).

2. Usar msg.sender en lugar de tx.origin

tx.origin devuelve la cuenta externa original que inició la transacción. Si un contrato malicioso llama a tu contrato a través de la cuenta del atacante, tx.origin será el atacante, lo que puede eludir la autenticación.

// Malo: usa tx.origin para autorización
function withdraw() public {
    require(tx.origin == owner, "No es el propietario");
    // ...
}

// Bueno: usa msg.sender
function withdraw() external {
    require(msg.sender == owner, "No es el propietario");
    // ...
}

Usa siempre msg.sender para autenticación directa.

3. Usar modificadores de visibilidad adecuadamente

Declara explícitamente la visibilidad de funciones y variables de estado. Las funciones y variables públicas son accesibles externamente; usa external para funciones llamadas solo desde fuera del contrato para ahorrar gas. Marca las funciones internas como internal y las privadas como private.

contract VisibilityExample {
    uint256 private secretNumber; // solo este contrato
    string public name; // cualquiera puede leer

    function doSomething() external { /* ... */ }
    function _helper() internal { /* ... */ } // solo contratos derivados
}

4. Evitar usar delegatecall con contratos no confiables

delegatecall ejecuta código de otro contrato en el contexto del llamante. Una implementación maliciosa puede cambiar el almacenamiento o drenar fondos. Si debes usar proxies, sigue patrones establecidos como el proxy transparente o UUPS de OpenZeppelin.

// Riesgoso: delegar a una dirección arbitraria
function execute(address _impl, bytes memory _data) public {
    (bool success, ) = _impl.delegatecall(_data);
    require(success);
}

5. Usar SafeMath para Solidity <0.8.0

Si trabajas con una versión anterior de Solidity, usa siempre la librería SafeMath de OpenZeppelin para prevenir desbordamientos aritméticos. Desde Solidity 0.8.0, las comprobaciones de desbordamiento están incorporadas.

6. Control de acceso con OpenZeppelin

En lugar de codificar una dirección de propietario, usa un sistema basado en roles.

import "@openzeppelin/contracts/access/AccessControl.sol";

contract MyToken is AccessControl {
    bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");

    function mint(address to, uint256 amount) public onlyRole(MINTER_ROLE) {
        _mint(to, amount);
    }
}

Pruebas y monitoreo con RPC confiable

La seguridad no termina en el despliegue. El monitoreo continuo de transacciones en cadena e interacciones con contratos es esencial. Un proveedor de RPC confiable te ofrece:

  • Puntos finales de alta disponibilidad para monitorear eventos en tiempo real.
  • Acceso a datos de archivo para análisis histórico de transacciones sospechosas.
  • Conexiones de baja latencia para detección rápida de explotaciones.

Usar un servicio de nodo dedicado como OnFinality permite que tus scripts de monitoreo automatizados consulten la cadena sin límites de tasa durante incidentes críticos. Revisa nuestras redes compatibles y precios de RPC para planificar tu infraestructura.

Uso de Trace API para análisis de seguridad

Para detectar reentrancia o delegatecalls maliciosos, puedes usar la API debug_traceTransaction (Ethereum) para recorrer paso a paso la ejecución de una transacción. Esto requiere un nodo de archivo con trazado habilitado.

curl -X POST <RPC_ENDPOINT> -H "Content-Type: application/json" -d '{
  "jsonrpc": "2.0",
  "method": "debug_traceTransaction",
  "params": ["0x...txhash"],
  "id": 1
}'

Asegúrate de que tu proveedor de RPC admita métodos de archivo y trazado antes de comprometerte con una plataforma.

Herramientas de seguridad y auditorías

Antes de desplegar, ejecuta herramientas automatizadas de análisis estático:

  • Slither: detecta vulnerabilidades comunes y genera gráficos de funciones.
  • Mythril: motor de ejecución simbólica que busca errores de seguridad.
  • Echidna: herramienta de fuzzing basada en propiedades.
  • Surya: visualiza el flujo de control del contrato.

Además, considera una auditoría profesional de firmas como ConsenSys Diligence o Trail of Bits. Combina escaneos automatizados con revisión manual para una cobertura integral.

Conclusiones clave

  1. Siempre usa guardas de reentrancia y sigue el patrón de verificaciones-efectos-interacciones.
  2. Elige Solidity 0.8+ o SafeMath para prevenir desbordamientos de enteros.
  3. Usa msg.sender para autenticación y modificadores de visibilidad explícitos.
  4. Evita delegatecall con contratos no confiables; usa patrones de proxy con cuidado.
  5. Prueba exhaustivamente en testnets usando puntos finales RPC confiables.
  6. Monitorea contratos en producción con infraestructura RPC de alta disponibilidad.

Preguntas frecuentes

P: ¿Cómo elijo un proveedor de RPC para monitoreo de seguridad? R: Busca proveedores que ofrezcan datos de archivo, APIs de trazado y soporte WebSocket. Evalúa su SLA de tiempo de actividad y límites de tasa según tu frecuencia de monitoreo. Compara opciones.

P: ¿Debo usar un punto final RPC privado para mi contrato inteligente? R: Para monitoreo en producción y extracción de datos sensibles, un punto final RPC dedicado reduce el riesgo de límites de tasa y asegura un rendimiento consistente. Los puntos finales públicos son adecuados para pruebas ligeras.

P: ¿Puedo confiar en las comprobaciones de desbordamiento incorporadas de Solidity? R: Desde Solidity 0.8.0, las comprobaciones de desbordamiento están habilitadas por defecto. Para versiones anteriores, debes usar SafeMath o el bloque unchecked (si estás seguro de que la operación no puede desbordarse).

P: ¿Cuál es la mejor manera de probar la reentrancia? R: Usa pruebas unitarias con contratos mock que simulen llamadas recursivas. Herramientas como Foundry te permiten escribir tales pruebas en Solidity. Además, ejecuta análisis estático con el detector de reentrancia de Slither.

Base de conocimiento RPC

Detalles RPC relacionados

Nunca te preocupes por la infraestructura nuevamente

OnFinality elimina la carga pesada de DevOps para que puedas construir de forma más inteligente y rápida.

Comenzar