Anti-pattern: utilizza quantificatori greedy nel criterio RegularExpressionProtection

Stai visualizzando la documentazione di Apigee Edge.
Vai alla documentazione di Apigee X.
informazioni

Il criterio RegularExpressionProtection definisce le espressioni regolari che vengono valutate in fase di runtime su parametri di input o variabili di flusso. In genere questo criterio viene utilizzato per proteggerti da minacce ai contenuti come SQL o JavaScript injection o per controllare la presenza di parametri di richiesta non corretti, come indirizzi email o URL.

Le espressioni regolari possono essere definite per percorsi di richiesta, parametri di query, parametri di modulo, intestazioni, elementi XML (in un payload XML definito mediante XPath), attributi di oggetti JSON (in un payload JSON definito tramite JSONPath).

Il criterio RegularExpressionProtection di esempio seguente protegge il backend dagli attacchi di 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 ingordi in natura: iniziano a corrispondere con la sequenza più lunga possibile. Se non viene trovata alcuna corrispondenza, tornano gradualmente per cercare di trovare una corrispondenza. Se la stringa risultante che corrisponde al pattern è molto breve, l'uso di quantificatori ingordi può richiedere più tempo del necessario. Ciò è particolarmente vero se il payload è di grandi dimensioni (nell'ordine delle decine o delle 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, l'intera stringa. Se non viene trovata alcuna corrispondenza, la norma torna indietro gradualmente. Se la stringa corrispondente si trova vicino all'inizio o alla metà del payload, l'utilizzo di un quantificatore ingordo come .* può richiedere molto più tempo e potenza di elaborazione rispetto a qualificatori riluttanti come .*? o (meno comunemente) quantificatori proprietari come .*+.

I quantificatori riluttanti (come X*?, X+?, X??) iniziano cercando di trovare la corrispondenza con un singolo carattere all'inizio del payload e aggiungono gradualmente caratteri. I quantificatori Possessivi (come X?+, X*+ e X++) tentano di abbinare l'intero payload solo una 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.

In questo caso, l'utilizzo dell'app .* greedy non garantisce un rendimento ottimale. Per la corrispondenza del pattern .*Exception in thread.* sono necessari 141 passi. Se invece hai utilizzato il pattern .*?Exception in thread.* (che utilizza un quantificatore riluttante), il risultato sarebbero solo 55 passaggi.

Impatto

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

  • Un aumento della latenza complessiva per le richieste API per una dimensione del payload moderata (fino a 1 MB)
  • Tempi più lunghi per il completamento dell'esecuzione del criterio RegularExpressionProtection
  • Richieste API con payload di grandi dimensioni (> 1 MB) che non generano errori con 504 errori di timeout del gateway se scade il periodo di timeout predefinito sul router perimetrale
  • Elevato utilizzo della CPU sui processori di messaggi a causa dell'elevata quantità di elaborazione che può influire ulteriormente su altre richieste API

Best practice

  • Evita di utilizzare quantificatori ingordi come .* nelle espressioni regolari con il criterio RegularExpressionProtection. Se possibile, utilizza invece quantificatori riluttanti come .*? o quantificatori possessori come .*+ (meno comunemente).

Per approfondire