Antipadrão: quantificadores ávidos na política regularExpressionProtection

Esta é a documentação da Apigee e da Apigee híbrida.
Confira a documentação da Apigee Edge.

A política RegularExpressionProtection define expressões regulares que são avaliadas no ambiente de execução em parâmetros de entrada ou variáveis de fluxo. Normalmente, essa política é usada para proteção contra ameaças de conteúdo, como injeção de SQL ou JavaScript, ou para verificar parâmetros de solicitação incorretos, como endereços de e-mail ou URLs.

As expressões regulares podem ser definidas para caminhos de solicitação, parâmetros de consulta, parâmetros de formulário, cabeçalhos e elementos XML (em um payload XML definido usando Xcode), atributos de objeto JSON (em um payload JSON definido usando JSONPath).

O exemplo a seguir da política RegularExpressionProtection protege o back-end contra ataques de injeção 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>

Antipadrão

Os quantificadores padrão (*, + e ?) são ávidos por natureza: eles começam a corresponder com a sequência mais longa possível. Quando nenhuma correspondência é encontrada, elas voltam gradualmente para tentar corresponder ao padrão. Se a string resultante correspondente ao padrão for muito curta, o uso de quantificadores ávidos poderá levar mais tempo do que o necessário. Isso é especialmente verdadeiro se o payload for grande (em dezenas ou centenas de KB).

O exemplo de expressão a seguir usa várias instâncias de .*, que são operadores ávidos:

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

Neste exemplo, a política RegularExpressionProtection primeiro tenta corresponder a maior sequência possível: a string inteira. Se nenhuma correspondência for encontrada, a política será executada gradualmente. Se a string correspondente estiver próxima ao início ou meio do payload, o uso de um quantificador ávido, como .*, poderá levar muito mais tempo e poder de processamento do que qualificadores relutantes como .*? ou (menos comum) quantificadores de posse, como .*+.

Os quantificadores relutantes (como X*?, X+?, X??) começam tentando corresponder a um único caractere desde o início do payload e adicionam caracteres gradualmente. Os quantificadores possíveis (como X?+, X*+, X++) tentam corresponder todo o payload apenas uma vez.

Dado o seguinte exemplo de texto para o padrão acima:

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

O uso da .* ávida não tem desempenho neste caso. O padrão .*Exception in thread.* usa 141 etapas para corresponder. Em vez disso, se você usar o padrão .*?Exception in thread.* (que usa um quantificador relutante), o resultado seria apenas 55 etapas.

Impacto

O uso de quantificadores ávidos como caracteres curinga (*) com a política RegularExpressionProtection pode levar a:

  • Aumento na latência geral de solicitações de API para um tamanho de payload moderado (até 1 MB)
  • Maior tempo para concluir a execução da política RegularExpressionProtection
  • Solicitações de API com payloads grandes (mais de 1 MB) com falhas e erros de tempo limite de gateway de 504 se o período de tempo limite predefinido esgotar no roteador da Apigee
  • Alta utilização da CPU em processadores de mensagens devido à grande quantidade de processamento, que pode afetar ainda mais as outras solicitações da API

Prática recomendada

  • Evite usar quantizadores ávidos, como .*, em expressões regulares com a política RegularExpressionProtection. Em vez disso, use quantificadores relutantes como .*? ou quantificadores possessivos como .*+ (menos comumente) sempre que possível.

Leitura adicional