Antipattern: utilizzare quantificatori greedy nel criterio RegularExpressionProtection

Stai visualizzando la documentazione di Apigee e Apigee hybrid.
Visualizza la documentazione di Apigee Edge.

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, questa policy viene utilizzata per proteggersi da minacce ai contenuti come SQL injection o JavaScript injection oppure 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, parametri di ricerca, 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 criterio RegularExpressionProtection di esempio 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 avidi per natura: iniziano a corrispondere alla sequenza più lunga possibile. Quando non viene trovata alcuna corrispondenza, i personaggi tornano indietro gradualmente per cercare di 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 sequenza più lunga possibile, ovvero l'intera stringa. Se non viene trovata alcuna corrispondenza, la policy fa un passo indietro gradualmente. Se la stringa corrispondente si trova 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 riluttanti come .*? o (meno comunemente) ai quantificatori possessivi come .*+.

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

Dato il seguente testo di esempio per il pattern precedente:

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

L'utilizzo di .* greedy non è efficiente in questo caso. Il pattern .*Exception in thread.* richiede 141 passaggi per la corrispondenza. Se invece avessi utilizzato il pattern .*?Exception in thread.* (che utilizza un quantificatore riluttante), il risultato sarebbe stato di soli 55 passi.

Impatto

L'utilizzo di quantificatori greedy come 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)
  • Tempo più lungo per completare l'esecuzione della policy 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 Apigee
  • 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 riluttanti come .*? o quantificatori possessivi come .*+ (meno comunemente) ovunque possibile.

Per approfondire