Antipattern: usa quantificatori greedy nel criterio RegularExpressionProtection

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

Il criterio RegularExpressionProtection definisce espressioni regolari valutate in fase di runtime in parametri di input o variabili di flusso. In genere, questo criterio viene utilizzato per proteggerti da minacce relative ai contenuti come SQL injection o JavaScript oppure per verificare che non ci siano parametri di richiesta con formato non corretto, come indirizzi email o URL.

È possibile definire espressioni regolari per percorsi di richiesta, parametri di ricerca, parametri del modulo, intestazioni, elementi XML (in un payload XML definito mediante XPath), attributi di oggetti JSON (in un payload JSON definito utilizzando JSONPath).

Il seguente 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 in natura: iniziano ad avere corrispondenze con la sequenza più lunga possibile. Quando non trova corrispondenze, tornano gradualmente per cercare di trovare lo schema. Se la stringa risultante che corrisponde al pattern è molto corta, l'uso di quantificatori avidi può richiedere più tempo del necessario. Ciò è particolarmente vero se il payload è di grandi dimensioni (nelle 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 prima di trovare la sequenza più lunga possibile, ovvero l'intera stringa. Se non viene trovata alcuna corrispondenza, il criterio torna indietro gradualmente. Se la stringa corrispondente si trova vicino all'inizio o alla metà del payload, l'utilizzo di un quantificatore greedy come .* può richiedere molto più tempo e potenza di elaborazione rispetto ai qualificatori riluttanti come .*? o (meno comunemente) ai quantificatori proprietari come .*+.

I quantificatori riluttanti (come X*?, X+?, X??) iniziano cercando di trovare la corrispondenza di un singolo carattere dall'inizio del payload e aggiungono caratteri gradualmente. I quantificatori propositivi (come X?+, X*+, X++) tentano di abbinare 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 dello standard .* greedy non è efficace. Per la corrispondenza del pattern .*Exception in thread.* sono necessari 141 passaggi. Se invece utilizzassi il pattern .*?Exception in thread.* (che utilizza un quantificatore rilutante), il risultato sarebbe di soli 55 passaggi.

Impatto

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

  • Un aumento della latenza complessiva per le richieste API per una dimensione del payload moderata (fino a 1 MB)
  • Tempi di esecuzione più lunghi per il criterio RegularExpressionProtection
  • Richieste API con payload di grandi dimensioni (> 1 MB) che non superano 504 errori di timeout del gateway se trascorre il periodo di timeout predefinito sul router Apigee
  • Elevato utilizzo della CPU nei processori di messaggi a causa dell'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 quantificatori riluttanti come .*? o quantificatori possessivi come .*+ (meno comunemente).

Per approfondire