Saltar al contenido principal

Pautas de seguridad para contratos inteligentes

Solidity
contratos inteligentes
seguridad
Intermedio
Trailofbits
6 de septiembre de 2020
5 minutos de lectura

Sigue estas recomendaciones de alto nivel para construir contratos inteligentes más seguros.

Pautas de diseño

El diseño del contrato debe discutirse con anticipación, antes de escribir cualquier línea de código.

Documentación y especificaciones

La documentación puede escribirse en diferentes niveles y debe actualizarse mientras se implementan los contratos:

Computación en cadena frente a fuera de la cadena

  • Mantén la mayor cantidad de código posible fuera de la cadena. Mantén la capa en cadena pequeña. Preprocesa los datos con código fuera de la cadena de tal manera que la verificación en cadena sea simple. ¿Necesitas una lista ordenada? Ordena la lista fuera de la cadena y luego solo verifica su orden en cadena.

Capacidad de actualización

Discutimos las diferentes soluciones de capacidad de actualización en nuestra publicación de blog (se abre en una pestaña nueva). Toma una decisión deliberada sobre si admitir o no la capacidad de actualización antes de escribir cualquier código. La decisión influirá en cómo estructures tu código. En general, recomendamos:

  • Favorecer la migración de contratos (se abre en una pestaña nueva) sobre la capacidad de actualización. Los sistemas de migración tienen muchas de las mismas ventajas que los actualizables, sin sus inconvenientes.
  • Usar el patrón de separación de datos sobre el de delegatecallproxy. Si tu proyecto tiene una clara separación de abstracción, la capacidad de actualización mediante la separación de datos requerirá solo unos pocos ajustes. El delegatecallproxy requiere experiencia en la EVM y es muy propenso a errores.
  • Documentar el procedimiento de migración/actualización antes del despliegue. Si tienes que reaccionar bajo estrés sin ninguna pauta, cometerás errores. Escribe el procedimiento a seguir con anticipación. Debe incluir:
    • Las llamadas que inician los nuevos contratos
    • Dónde se almacenan las claves y cómo acceder a ellas
    • ¡Cómo verificar el despliegue! Desarrolla y prueba un script posterior al despliegue.

Pautas de implementación

Esfuérzate por la simplicidad. Usa siempre la solución más simple que se adapte a tu propósito. Cualquier miembro de tu equipo debería poder entender tu solución.

Composición de funciones

La arquitectura de tu código base debería hacer que tu código sea fácil de revisar. Evita las decisiones arquitectónicas que disminuyan la capacidad de razonar sobre su corrección.

  • Divide la lógica de tu sistema, ya sea a través de múltiples contratos o agrupando funciones similares (por ejemplo, autenticación, aritmética, ...).
  • Escribe funciones pequeñas, con un propósito claro. Esto facilitará la revisión y permitirá probar componentes individuales.

Herencia

  • Mantén la herencia manejable. La herencia debe usarse para dividir la lógica; sin embargo, tu proyecto debe apuntar a minimizar la profundidad y el ancho del árbol de herencia.
  • Usa el impresor de herencia (se abre en una pestaña nueva) de Slither para verificar la jerarquía de los contratos. El impresor de herencia te ayudará a revisar el tamaño de la jerarquía.

Eventos

  • Registra todas las operaciones cruciales. Los eventos ayudarán a depurar el contrato durante el desarrollo y a monitorearlo después del despliegue.

Evita los errores conocidos

Dependencias

  • Usa bibliotecas bien probadas. Importar código de bibliotecas bien probadas reducirá la probabilidad de que escribas código con errores. Si quieres escribir un contrato ERC-20, usa OpenZeppelin (se abre en una pestaña nueva).
  • Usa un administrador de dependencias; evita copiar y pegar código. Si dependes de una fuente externa, debes mantenerla actualizada con la fuente original.

Pruebas y verificación

Solidity

  • Favorece Solidity 0.5 sobre 0.4 y 0.6. En nuestra opinión, Solidity 0.5 es más seguro y tiene mejores prácticas integradas que 0.4. Solidity 0.6 ha demostrado ser demasiado inestable para producción y necesita tiempo para madurar.
  • Usa una versión estable para compilar; usa la última versión para comprobar si hay advertencias. Verifica que tu código no tenga problemas reportados con la última versión del compilador. Sin embargo, Solidity tiene un ciclo de lanzamiento rápido y un historial de errores en el compilador, por lo que no recomendamos la última versión para el despliegue (consulta la recomendación de versión de solc (se abre en una pestaña nueva) de Slither).
  • No uses ensamblador en línea. El ensamblador requiere experiencia en la EVM. No escribas código de la EVM si no dominas el Libro Amarillo.

Pautas de despliegue

Una vez que el contrato ha sido desarrollado y desplegado:

  • Monitorea tus contratos. Observa los registros y prepárate para reaccionar en caso de que el contrato o la billetera se vean comprometidos.
  • Agrega tu información de contacto a blockchain-security-contacts (se abre en una pestaña nueva). Esta lista ayuda a terceros a contactarte si se descubre una falla de seguridad.
  • Asegura las billeteras de los usuarios privilegiados. Sigue nuestras mejores prácticas (se abre en una pestaña nueva) si almacenas claves en billeteras de hardware.
  • Ten un plan de respuesta a incidentes. Considera que tus contratos inteligentes pueden verse comprometidos. Incluso si tus contratos no tienen errores, un atacante podría tomar el control de las claves del propietario del contrato.