Antipattern: utilizzare quantificatori greedy nel criterio RegularExpressionProtection

Stai visualizzando la documentazione di Apigee Edge.
Consulta la documentazione di Apigee X.
info

Il criterio RegularExpressionProtection definisce le espressioni regolari che vengono valutate in fase di runtime sui parametri di input o sulle variabili di flusso. In genere, questo criterio viene utilizzato per proteggersi dalle minacce ai contenuti, come SQL injection o JavaScript injection, o per verificare la presenza di parametri di richiesta non validi, come indirizzi email o URL.

Le espressioni regolari possono essere definite per i percorsi delle richieste, i parametri di query, i parametri del modulo, le intestazioni, gli elementi XML (in un payload XML definito utilizzando XPath), gli attributi degli oggetti JSON (in un payload JSON definito utilizzando JSONPath).

Il seguente esempio di criterio RegularExpressionProtection protegge il backend dagli attacchi SQL injection:

<!-- /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>

Antipattern

I quantificatori predefiniti (*, + e ?) sono di tipo greedy: iniziano a trovare corrispondenze con la sequenza più lunga possibile. Se non viene trovata alcuna corrispondenza, eseguono un backtracking graduale per provare a trovare una corrispondenza con il pattern. Se la stringa risultante che corrisponde al pattern è molto breve, l'utilizzo di quantificatori greedy può richiedere più tempo del necessario. Ciò è particolarmente vero se il payload è di grandi dimensioni (decine o centinaia di KB).

La seguente espressione di esempio utilizza più istanze di .*, che sono operatori greedy:

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

In questo esempio, il criterio RegularExpressionProtection tenta innanzitutto di trovare la corrispondenza con la sequenza più lunga possibile , ovvero l'intera stringa. Se non viene trovata alcuna corrispondenza, il criterio esegue un backtracking graduale. Se la stringa corrispondente si trova vicino all'inizio o al centro del payload, l'utilizzo di un quantificatore greedy come .* può richiedere molto più tempo e potenza di elaborazione rispetto ai quantificatori reluctant come .*? o (meno comunemente) ai quantificatori possessive come .*+.

I quantificatori reluctant (come X*?, X+?, X??) iniziano provando a trovare la corrispondenza con un singolo carattere dall'inizio del payload e aggiungono gradualmente i caratteri. I quantificatori possessive (come X?+, X*+, X++) tentano di trovare la corrispondenza con l'intero payload una sola volta.

Dato il seguente testo di esempio per il pattern riportato sopra:

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

In questo caso, l'utilizzo di .* greedy non è efficiente. Il pattern .*Exception in thread.* richiede 141 passaggi per trovare una corrispondenza. Se invece utilizzi il pattern .*?Exception in thread.* (che utilizza un quantificatore reluctant), il risultato sarà di soli 55 passaggi.

Impatto

L'utilizzo di quantificatori greedy come i caratteri jolly (*) con il criterio RegularExpressionProtection può comportare:

  • Un aumento della latenza complessiva per le richieste API per una dimensione del payload moderata (fino a 1 MB)
  • Un tempo più lungo per completare l'esecuzione del criterio RegularExpressionProtection
  • Richieste API con payload di grandi dimensioni (> 1 MB) che generano errori di timeout del gateway 504 se il periodo di timeout predefinito scade sul router Edge
  • Un utilizzo elevato della CPU sui processori di messaggi a causa della grande quantità di elaborazione, che può influire ulteriormente su altre richieste API

Best practice

  • Evita di utilizzare quantificatori greedy come .* nelle espressioni regolari con il criterio RegularExpressionProtection. Utilizza invece quantificatori reluctant come .*? o quantificatori possessive come .*+ (meno comunemente) ove possibile.

Per approfondire