Anti-pattern: utilizza 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 su parametri di input o variabili di flusso. In genere, questo criterio viene utilizzato per proteggerti da minacce ai contenuti come l'iniezione SQL o JavaScript oppure per verificare 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 ricerca, parametri di modulo, intestazioni, elementi XML (in un payload XML definito mediante XPath) e attributi di oggetti JSON (in un payload JSON definito mediante JSONPath).

Il criterio RegularExpressionProtection di esempio riportato di seguito 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 greedy in natura: iniziano ad corrispondere alla 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, ovvero l'intera stringa. Se non viene trovata alcuna corrispondenza, il criterio torna indietro gradualmente. Se la stringa corrispondente è vicina all'inizio o a metà del payload, l'utilizzo di un quantificatore greedy come .* può richiedere molto più tempo e una potenza di elaborazione superiore rispetto a qualificatori riluttanti come .*? o (meno comunemente) quantificatori proprietari come .*+.

I quantificatori riluttanti (come X*?, X+?, X??) iniziano cercando di abbinare un singolo carattere all'inizio del payload e aggiungono gradualmente i caratteri. I quantificatori proprietari (come X?+, X*+, X++) tentano di trovare corrispondenze 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.

In questo caso, l'utilizzo dell'app .* greedy non consente un rendimento ottimale. Per trovare la corrispondenza con il pattern .*Exception in thread.*, sono necessari 141 passi. Se invece hai utilizzato il pattern .*?Exception in thread.* (che utilizza un quantificatore riluttante), il risultato sarà di soli 55 passaggi.

Impatto

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

  • Aumento della latenza complessiva per le richieste API per un payload di dimensioni moderate (fino a 1 MB)
  • Tempi di completamento più lunghi per il completamento dell'esecuzione della norma RegularExpressionProtection
  • Richieste API con payload di grandi dimensioni (> 1 MB) non riuscite con 504 errori di timeout del gateway se scade il periodo di timeout predefinito sul router Apigee
  • Elevato utilizzo della CPU sui processori di messaggi a causa di un'elevata 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. Se possibile, utilizza invece quantificatori riluttanti come .*? o quantificatori proprietari come .*+ (meno comunemente).

Per approfondire