Aprenda cómo prevenir los ataques de denegación de servicio (DOS) en contratos inteligentes asegurando que las colas sean seguras, manejando tokens bajos decimales y administrando de forma segura llamadas externas.
Bienvenido de nuevo a la serie de resolución de la lista de verificación de Solodit . Continuaremos explorando las listas de verificación de auditoría de contratos inteligentes Solodit, centrándonos en estrategias prácticas para escribir contratos inteligentes seguros y resistentes.
Esta lista de verificación lo ayuda a identificar posibles vulnerabilidades e implementar medidas de seguridad proactivas. En la sección anterior " Resolución de la lista de verificación Solodit (1) ", examinamos tres listas de verificación ( patrón de extracción, cantidad mínima de transacción y lista negra ) relacionadas con un ataque de denegación de servicio (DOS) y proporcionó soluciones para los desarrolladores. Si aún no lo ha leído, le recomiendo ver el artículo antes de continuar.
En este artículo, discutiremos otros tres ítems en la lista de verificación, centrándonos nuevamente en los ataques de DOS. Nos sumergiremos en las vulnerabilidades de manejo de la cola , los desafíos planteados por los tokens bajos decimales y la importancia de manejar las llamadas de contratos externos de manera segura .
Para la mejor experiencia, abra una etiqueta de lista de verificación Solodit como referencia.
Esto es lo que discutiremos hoy:
Sol-Am-Dosa-4: Manejo de la cola de bloqueo : este problema ocurre cuando un atacante manipula la cola para detener o interrumpir sus operaciones, lo que resulta en DOS. Veremos cómo los atacantes pueden destruir las colas de procesamiento.
SOL-AM-DOSA-5: tokens bajos decimales : problemas que ocurren cuando se trata de tokens con lugares bajos en decimales. El cálculo, especialmente la división, puede truncarse a cero, lo que resulta en un comportamiento inesperado y dañino. Estos tokens de baja precisión pueden causar problemas con la división de enteros, interfiriendo así con funciones clave.
SOL-AM-DOSA-6: Llamadas externas inseguras : exploraremos cómo confiar en los contratos externas sin el manejo adecuado de errores para crear vulnerabilidades. Cuando la falla de una llamada externa no se maneja correctamente, puede hacer que todo el contrato regrese .
Los ataques del mundo real demuestran el daño potencial que estas vulnerabilidades pueden causar. El proyecto sufrió grandes pérdidas debido a una negligencia aparentemente menor.
Las listas de verificación Solodit se basan en hallazgos de auditoría, informes de recompensas de vulnerabilidad y eventos del mundo real. Al estudiar estas listas de verificación, puede aprender de errores pasados y mejorar la seguridad de su código .
Ahora, veamos cada elemento de verificación uno por uno a través del código de muestra. Estos ejemplos se han simplificado para resaltar las vulnerabilidades centrales.
Problema : si su contrato inteligente depende de una cola para el procesamiento de tareas, un atacante puede manipular un estado específico en la cola para evitar el procesamiento correcto.
Pregunta de la lista de verificación : "¿Puede un atacante bloquear o evitar el procesamiento de la cola para causar la interrupción del servicio?"
Solución : El mecanismo de manejo de la cola requiere un poderoso manejo de errores y mecanismos de retroceso para garantizar que los problemas puedan continuar procesando incluso si ocurren.
Ejemplo :
Considere un ejemplo de extraer una cola:
El usuario solicita la extracción y algunos indicadores indican que la solicitud está activa.
El atacante puede usar la función resetUserStatus
después de que la extracción esté eneada para evitar la misma operación de otros usuarios.
// 易受攻击的函数:可以被利用function resetUserStatus() external { // 任何人在仍然处于队列中的情况下都可以重置他们的状态withdrawalRequested[msg.sender] = false; // 注意:用户没有被移出队列! } // 处理队列中的下一次提取function processNextWithdrawal() external { require(withdrawalQueue.length > currentIndex, "没有可处理的提取"); // 获取下一次提取Withdrawal memory withdrawal = withdrawalQueue[currentIndex]; // 可被攻击者利用:此检查可能会被重置状态所攻击require(withdrawalRequested[withdrawal.user], "提取请求不再有效"); // 处理提取uint256 amount = withdrawal.amount; require(balances[withdrawal.user] >= amount, "余额不足"); // 更新余额balances[withdrawal.user] -= amount; // 重置提取请求withdrawalRequested[withdrawal.user] = false; // 发送资金(bool success, ) = payable(withdrawal.user).call{value:amount}(""); require(success, "资金发送失败"); // 移动到队列中的下一个currentIndex++; }
Para aprovechar esto, un atacante puede hacer lo siguiente:
resetUserStatus
.processNextWithdrawal
retrocederá, causando un ataque de DOS continuo.Remedios :
withdrawalRequested
al administrador.Problema : las fichas con lugares bajos en decimales pueden causar problemas de división entera, así que redondeando a cero .
Imagine un contrato de transmisión de tokens que asigna tokens durante un período de tiempo. Si tokensPerSecond
se redondea a cero debido a la división entera con tokens bajos decimales, la función de asignación se bloqueará. Pregunta de la lista de verificación : "¿Los tokens bajos decimales conducen a DOS?" Solución : Implemente la lógica para manejar puntos bajos decimales para evitar la interrupción de los procesos de negociación debido a errores de redondeo. Ejemplo :
Considere un contrato TokenStream
que transmite regularmente un cierto número de tokens a los usuarios, donde:
total_tokens
debe transferirse al contratotoken_per_second
puede redondearse a cero porque estamos usando tokens con un punto decimal de 1distributeTokens
retrocederá contract TokenStream { IERC20 public token; uint256 public streamDuration; uint256 public tokensPerSecond; constructor(IERC20 _token, uint256 _streamDuration, uint256 _tokensPerSecond) { token = _token; streamDuration = _streamDuration; tokensPerSecond = _tokensPerSecond; } function distributeTokens(address recipient) external { uint256 balance = token.balanceOf(address(this)); uint256 amount = tokensPerSecond * streamDuration; uint256 tokensToSend = amount > balance ? balance : amount; require(tokensToSend > 0, "没有足够的代币进行流送"); token.transfer(recipient, tokensToSend); } } contract LowDecimalToken is ERC20 { constructor() ERC20("LowDecimalToken", "LDT") { _mint(msg.sender, 100000 * (10 ** decimals())); } function decimals() public view virtual override returns (uint8) { return 1; // 模拟小数点为低的代币} }
En este caso, la prueba testDOSWithLowDecimalTokens
en TokenStreamTest
se volverá hacia atrás.
Remedio : Asegúrese de que el contrato maneje los tokens bajos decimales correctamente, aliviando los problemas causados por el redondeo de enteros durante el proceso de cálculo al ampliar las fórmulas matemáticas .
Problema : muchos contratos inteligentes dependen de contratos externos para interactuar. El comportamiento inesperado de los contratos externos puede hacer que todo el sistema regrese . No manejar estos errores externos puede conducir a vulnerabilidades de DOS.
Pregunta de la lista de verificación : "¿El protocolo maneja las interacciones del contrato externas de manera segura?"
Solución : Asegure un fuerte manejo de errores para interacciones contractuales externas para proteger la integridad del protocolo independientemente del rendimiento de los contratos externas.
Ejemplo : Considere un contrato que interactúa con una fuente de datos de precios de enlace de cadena externa. Si no utiliza Try/Catch para el manejo de errores adecuado, cualquier reversión de fuentes de datos externas se propagará al superior y hará que el contrato vuelva a revertir.
getPrice
recupera los datos de precios.calculateSomethingImportant
la función de tintieta importante depende de getPrice
y también retrocedirá. contract PriceDependentContract { AggregatorV3Interface public priceFeed; constructor(address _priceFeed) { priceFeed = AggregatorV3Interface(_priceFeed); } // 易受攻击的函数,在没有处理可能的Chainlink 回滚的情况下获取价格function getPrice() public view returns (uint256) { (, int256 price, , , ) = priceFeed.latestRoundData(); // 易受攻击的行:没有错误处理require(price > 0, "价格必须为正"); return uint256(price); } function calculateSomethingImportant() public view returns (uint256) { uint256 price = getPrice(); // ... 使用价格的一些重要计算return price * 2; }
Remedio : Envuelva las llamadas de contrato externo en un bloque de try/captación para manejar errores de reversión e implementar valores de reversión o caché.
Nota : ¡Hay un caso de borde en el que el contrato externo consume intencionalmente gas , lo que también puede fallar en el bloque de captura! Discutiremos esto más tarde.
Exploramos tres cheques clave diseñados para mejorar la capacidad de su contrato inteligente para resistir los ataques de DOS: las vulnerabilidades de manejo de colas , desafíos asociados con tokens bajos decimales y la importancia de manejar interacciones contractuales externas de forma segura .
Recuerde que los ejemplos proporcionados están destinados a ilustrar vulnerabilidades centrales. Es muy importante comprender los principios básicos y adaptar estos conceptos a sus casos de uso específicos.
Al implementar estas sugerencias, puede mejorar significativamente la seguridad y la resistencia de sus contratos inteligentes.
Estén atentos para la siguiente parte de la serie de resolución de la lista de verificación de Solodit.
- Enlace original: cyfrin.io/blog/solodit-c ...
- Denglian Community AI Asistente traduce excelentes artículos de inglés para todos. Si hay alguna área donde la traducción no es comprensible, perdóname ~