Aikido

¿Por qué se debería proteger contra expresiones regulares lentas para prevenir ataques ReDoS?

Legibilidad

Regla
Proteger contra lento regulares lentas.
Expresiones regulares regulares con anidadas anidados o 
ambiguos ambiguos pueden causar catastróficas 
retroceso y rendimiento rendimiento.
Idiomas compatibles: 45+

Introducción

Las expresiones regulares pueden congelar su aplicación durante segundos o minutos con la entrada adecuada. El backtracking catastrófico ocurre cuando los motores de regex exploran rutas que aumentan exponencialmente al intentar hacer coincidir un patrón. Una regex como (a+)+b tarda microsegundos en coincidir con una entrada válida, pero puede tardar horas en rechazar una cadena de 'a' sin una 'b' final. Los atacantes explotan esto mediante ataques de Denegación de Servicio por Expresiones Regulares (ReDoS), enviando entradas maliciosas que hacen que su motor de expresiones regulares consuma el 100% de la CPU hasta que se agoten los tiempos de espera de la solicitud o el proceso falle.

Por qué es importante

Implicaciones de seguridad (ataques ReDoS): Un atacante puede paralizar su aplicación con una única solicitud que contenga una entrada maliciosa. La validación de correos electrónicos y los patrones de análisis de URL son objetivos comunes. A diferencia de los ataques DoS tradicionales que requieren ancho de banda, ReDoS solo necesita cargas útiles muy pequeñas.

Degradación del rendimiento: La entrada normal del usuario puede desencadenar un retroceso catastrófico, haciendo que los tiempos de respuesta se disparen de milisegundos a segundos. Esto crea una latencia impredecible que es difícil de depurar porque solo se manifiesta con patrones de entrada específicos.

Incidentes en producción: Una expresión regular (regex) vulnerable bloquea el bucle de eventos en Node.js o consume recursos del pool de hilos. A medida que las solicitudes se acumulan, la memoria aumenta y el sistema deja de responder. En microservicios, una regex vulnerable propaga fallos a los servicios dependientes.

Dificultad en la detección: Los patrones que funcionan bien en pruebas con entradas cortas se vuelven exponencialmente lentos con entradas más largas. La vulnerabilidad a menudo pasa desapercibida hasta la producción, requiriendo un despliegue de emergencia durante un incidente activo.

Ejemplos de código

❌ No conforme:

function validateEmail(email) {
    const regex = /^([a-zA-Z0-9_\-\.]+)+@([a-zA-Z0-9_\-\.]+)+\.([a-zA-Z]{2,5})$/;
    return regex.test(email);
}

function extractURLs(text) {
    const regex = /(https?:\/\/)?([\w\-])+\.(\w+)+([\w\-\.,@?^=%&:/~\+#]*)+/g;
    return text.match(regex);
}

Por qué es inseguro: Los cuantificadores anidados ([a-zA-Z0-9_\\-\\.]+)+ crear retroceso exponencial. Para un correo electrónico como aaaaaaaaaaaaaaaaaaaaaaaaa!, el motor de expresiones regulares intenta innumerables combinaciones antes de fallar. La expresión regular de URL tiene múltiples cuantificadores anidados que agravan el problema, haciéndola trivialmente explotable con entradas como cadenas largas de caracteres válidos sin la estructura esperada.

✅ Conforme:

function validateEmail(email) {
    const regex = /^[a-zA-Z0-9_\-\.]+@[a-zA-Z0-9_\-\.]+\.[a-zA-Z]{2,5}$/;
    return regex.test(email);
}

function extractURLs(text) {
    const regex = /https?:\/\/[\w\-]+\.[\w\-]+(?:[\w\-\.,@?^=%&:/~\+#]*)?/g;
    return text.match(regex);
}

Por qué es seguro: La eliminación de cuantificadores anidados elimina el backtracking catastrófico. Cuantificadores simples como [a-zA-Z0-9_\-\.]+ se ejecutan en tiempo lineal. El patrón de URL utiliza grupos no capturadores con sufijo opcional (?:...)? en lugar de repetición anidada, asegurando un rendimiento predecible independientemente de la longitud o el contenido de la entrada.

Conclusión

El rendimiento de las expresiones regulares es una preocupación de seguridad, no solo una optimización. Revise todos los patrones regex en busca de cuantificadores anidados, clases de caracteres superpuestas en grupos de repetición y alternativas ambiguas. Pruebe los patrones regex con entradas patológicas (cadenas largas de caracteres válidos seguidas de terminaciones inválidas) para identificar el backtracking catastrófico antes de la implementación. Cuando sea posible, reemplace las regex complejas con funciones de análisis de cadenas que tengan características de rendimiento predecibles.

Preguntas frecuentes

¿Tiene preguntas?

¿Qué patrones causan retroceso catastrófico?

Los culpables comunes incluyen cuantificadores anidados como (a+)+, (a*)*, o (a+)*b. Alternancia con patrones superpuestos como (a|a)* o (a|ab)*. Repetición con componentes opcionales como (a?)+. Cualquier patrón donde el motor de expresiones regulares pueda coincidir con la misma subcadena de múltiples formas crea un espacio de búsqueda exponencial. Preste atención a los cuantificadores (+, *, {n,m}) dentro de grupos que a su vez están cuantificados.

¿Cómo pruebo si mi regex es vulnerable a ReDoS?

Utilice herramientas en línea como regex101.com que muestran los pasos de ejecución y advierten sobre el backtracking catastrófico. Cree entradas de prueba con cadenas largas de caracteres válidos seguidas de caracteres que fuercen el backtracking. Para el patrón /^(a+)+b$/, pruebe con "aaaaaaaaaaaaaaa!" (más de 30 'a', sin 'b'). Si la ejecución tarda más de milisegundos, la expresión regular es vulnerable. Implemente tiempos de espera en las operaciones de expresiones regulares en producción como defensa en profundidad.

¿Cuál es la diferencia entre el retroceso catastrófico y lineal?

El retroceso lineal ocurre cuando la expresión regular (regex) intenta alternativas en secuencia, pero no reevalúa las elecciones anteriores. El trabajo crece linealmente con el tamaño de la entrada. El retroceso catastrófico ocurre cuando los cuantificadores anidados obligan al motor a probar un número exponencial de combinaciones. Para una entrada de longitud n, el tiempo de ejecución puede ser O(2^n) o peor. La diferencia es entre milisegundos y minutos para tamaños de entrada moderados.

¿Puedo usar aserciones de anticipación y retroceso de forma segura?

Lookaheads (?=...) and lookbehinds (?<=...) themselves don't cause catastrophic backtracking, but they can hide vulnerable patterns. A lookahead containing (a+)+ is still vulnerable. Use lookarounds for their intended purpose (assertions without consuming characters), not as a workaround for complex matching. Keep the patterns inside lookarounds simple and test them thoroughly.

¿Existen motores regex que prevengan el backtracking catastrófico?

RE2 (utilizado por Google) garantiza una ejecución en tiempo lineal al prohibir completamente el backtracking. No es compatible con todas las características (backreferences, lookarounds) pero previene ReDoS por completo. Para comprobaciones de seguridad críticas, considera usar bindings de RE2 o motores similares. Para JavaScript, no hay una alternativa integrada, por lo que el diseño de patrones y los timeouts son tus defensas principales.

¿Debería añadir timeouts a todas las operaciones de regex?

Para entradas no confiables (datos proporcionados por el usuario, respuestas de API externas), sí. Establezca tiempos de espera razonables, como 100-500ms, dependiendo de la complejidad esperada. En Node.js, no se puede establecer un tiempo de espera directamente para regex.test(), pero se puede validar primero la longitud de la entrada o ejecutar regex en un hilo de trabajo con tiempo de espera. Rechace las entradas que excedan los límites de longitud razonables antes de intentar la coincidencia de regex.

¿Cómo corrijo un patrón regex vulnerable existente?

Primero, determina si necesitas expresiones regulares (regex). Muchas tareas de validación son más sencillas con métodos de cadena como includes(), startsWith() o split(). Si las expresiones regulares son necesarias, elimina los cuantificadores anidados aplanando el patrón. Reemplaza (a+)+ por a+. Usa grupos atómicos o cuantificadores posesivos si tu motor de expresiones regulares los soporta. Para patrones complejos, considera analizar la entrada en múltiples pasadas con expresiones regulares u operaciones de cadena más simples.

Asegúrate ahora.

Proteja su código, la nube y el entorno de ejecución en un único sistema central.
Encuentre y corrija vulnerabilidades de forma rápida y automática.

No se requiere tarjeta de crédito | Resultados del escaneo en 32 segundos.