Antipatrón: utilizar cuantificadores expansivos en la política RegularExpressionProtection

Estás consultando la documentación de Apigee y Apigee Hybrid.
Consulta la documentación de Apigee Edge.

La política RegularExpressionProtection define expresiones regulares que se evalúan en tiempo de ejecución en los parámetros de entrada o las variables de flujo. Normalmente, esta política se usa para protegerse frente a amenazas de contenido, como la inyección de SQL o JavaScript, o para comprobar si los parámetros de solicitud están mal formados, como las direcciones de correo o las URLs.

Las expresiones regulares se pueden definir para rutas de solicitudes, parámetros de consulta, parámetros de formulario, encabezados, elementos XML (en una carga útil XML definida mediante XPath) y atributos de objetos JSON (en una carga útil JSON definida mediante JSONPath).

La siguiente política de RegularExpressionProtection protege el backend frente a ataques de inyección de SQL:

<!-- /antipatterns/examples/greedy-1.xml -->
<RegularExpressionProtection async="false" continueOnError="false" enabled="true"
  name="RegexProtection">
    <DisplayName>RegexProtection</DisplayName>
    <Properties/>
    <Source>request</Source>
    <IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
    <QueryParam name="query">
      <Pattern>[\s]*(?i)((delete)|(exec)|(drop\s*table)|
        (insert)|(shutdown)|(update)|(\bor\b))</Pattern>
    </QueryParam>
</RegularExpressionProtection>

Antipatrón

Los cuantificadores predeterminados (*, + y ?) son de naturaleza ávida: empiezan a buscar coincidencias con la secuencia más larga posible. Si no se encuentra ninguna coincidencia, retroceden gradualmente para intentar encontrar el patrón. Si la cadena resultante que coincide con el patrón es muy corta, usar cuantificadores ávidos puede llevar más tiempo del necesario. Esto es especialmente cierto si la carga útil es grande (decenas o cientos de KB).

En la siguiente expresión de ejemplo se usan varias instancias de .*, que son operadores ávidos:

<Pattern>.*Exception in thread.*</Pattern>

En este ejemplo, la política RegularExpressionProtection intenta primero encontrar la secuencia más larga posible, es decir, la cadena completa. Si no se encuentra ninguna coincidencia, la política retrocede gradualmente. Si la cadena coincidente está cerca del principio o de la mitad de la carga útil, usar un cuantificador ávido como .* puede llevar mucho más tiempo y potencia de procesamiento que los cuantificadores reacios, como .*?, o los cuantificadores posesivos, como .*+ (que se usan con menos frecuencia).

Los cuantificadores reacios (como X*?, X+? y X??) empiezan intentando buscar una coincidencia de un solo carácter desde el principio de la carga útil y van añadiendo caracteres gradualmente. Los cuantificadores posesivos (como X?+, X*+ y X++) intentan encontrar coincidencias en toda la carga útil solo una vez.

Teniendo en cuenta el siguiente texto de ejemplo para el patrón anterior:

Hello this is a sample text with Exception in thread
with lot of text after the Exception text.

En este caso, usar el .* ávido no es eficiente. El patrón .*Exception in thread.* tarda 141 pasos en coincidir. Si hubieras usado el patrón .*?Exception in thread.* (que usa un cuantificador reacio), el resultado sería de solo 55 pasos.

Impacto

Si se usan cuantificadores expansivos, como comodines (*), con la política RegularExpressionProtection, se pueden producir los siguientes problemas:

  • Un aumento de la latencia general de las solicitudes a la API para una carga útil de tamaño moderado (hasta 1 MB)
  • Más tiempo para completar la ejecución de la política RegularExpressionProtection
  • Las solicitudes a la API con cargas útiles grandes (> 1 MB) fallan con errores de tiempo de espera de la puerta de enlace 504 si se agota el periodo de tiempo de espera predefinido en el router de Apigee
  • Uso elevado de la CPU en los procesadores de mensajes debido a la gran cantidad de procesamiento, lo que puede afectar a otras solicitudes a la API.

Práctica recomendada

  • Evita usar cuantificadores expansivos, como .*, en expresiones regulares con la política RegularExpressionProtection. En su lugar, utiliza cuantificadores reacios, como .*?, o cuantificadores posesivos, como .*+ (menos habitual), siempre que sea posible.

Más información