Antipattern: utilizzare quantificatori greedy nel criterio RegularExpressionProtection

Stai visualizzando la documentazione relativa a Apigee e Apigee ibrido.
Visualizza Documentazione di Apigee Edge.

Il criterio RegularExpressionProtection definisce le espressioni regolari valutate in base il tempo di esecuzione sui parametri di input o sulle variabili di flusso. In genere utilizzi questo criterio per proteggerti da minacce nei contenuti come SQL injection o JavaScript oppure per verificare la presenza di parametri di richiesta non corretti come indirizzi email o URL.

È possibile definire espressioni regolari per percorsi di richiesta, parametri di ricerca, parametri intestazioni, elementi XML (in un payload XML definito utilizzando XPath), attributi degli oggetti JSON (in un file JSON payload 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 ingordi naturale: iniziano a corrispondere alla sequenza più lunga possibile. Quando non viene trovata alcuna corrispondenza, si ritirano gradualmente per cercare di trovare una corrispondenza con il pattern. Se la stringa risultante corrispondente al pattern è molto breve, l'uso di quantificatori avidi 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 greedy operatori:

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

In questo esempio, il criterio RegularExpressionProtection tenta innanzitutto di trovare la corrispondenza più lunga possibile sequenza: l'intera stringa. Se non viene trovata alcuna corrispondenza, la norma esegue un backtracking graduale. Se la stringa corrispondente è vicina all'inizio o alla metà del payload, l'uso di un quantificatore greedy come .* può richiedere molto più tempo e potenza di elaborazione rispetto ai riluttanti qualificatori come .*? o (meno comunemente) quantificatori possessivi come .*+.

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

L'utilizzo dell'algoritmo .* avido non è efficace in questo caso. Lo schema .*Exception in thread.* richiede 141 passi per abbinare. Se hai utilizzato lo schema .*?Exception in thread.* (che utilizza un quantificatore riluttante), il risultato essere di soli 55 passi.

Impatto

Utilizzo di quantificatori greedy come caratteri jolly (*) con Il criterio RegularExpressionProtection può causare:

  • Un aumento della latenza complessiva per le richieste API per una dimensione del payload moderata (fino a 1 MB)
  • Tempi più lunghi per completare l'esecuzione del criterio RegularExpressionProtection
  • Le richieste API con payload di grandi dimensioni (> 1 MB) non vanno a buon fine con errori di timeout del gateway 504 se il periodo di timeout predefinito scade sul router Apigee
  • Elevata occupazione della CPU nei processori di messaggi a causa di una grande quantità di elaborazione che può incidere ulteriormente su altre richieste API

Best practice

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

Per approfondire