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 esecuzione sui parametri di input o sulle variabili di flusso. In genere, questo criterio viene utilizzato per proteggersi dalle minacce ai contenuti come SQL o l'iniezione di JavaScript oppure per verificare la presenza di parametri di richiesta con formato non corretto come indirizzi email o URL.

Le espressioni regolari possono essere definite per percorsi di richiesta, parametri di query, parametri di modulo, parametri di intestazione, elementi XML (in un payload XML definito utilizzando XPath), attributi di 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 avidi per natura: iniziano a corrispondere con la 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 che corrisponde al pattern è molto breve, l'utilizzo di quantificatori avidi può richiedere più tempo del necessario. Ciò è particolarmente vero se il payload è di grandi dimensioni (decine o centinaia di KB).

L'espressione di esempio seguente utilizza più istanze di .*, che sono operatori avidi:

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

In questo esempio, il criterio RegularExpressionProtection tenta innanzitutto di trovare una corrispondenza con la sequenza più lunga possibile, ovvero l'intera stringa. Se non viene trovata alcuna corrispondenza, la norma esegue un backtracking graduale. Se la stringa corrispondente è vicina all'inizio o al centro del payload, l'utilizzo di un quantificatore avidi 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 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.

In questo caso, l'utilizzo dell'algoritmo .* avido non è efficace. La corrispondenza del pattern.*Exception in thread.* richiede 141 passaggi. Se avessi utilizzato il pattern .*?Exception in thread.* (che utilizza un quantificatore riluttante), il risultato sarebbe stato di soli 55 passaggi.

Impatto

L'utilizzo di quantificatori avidi 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)
  • Tempo più lungo per completare l'esecuzione della norma 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