Antimodèle : utiliser des quantificateurs gourmands en ressources dans la règle RegularExpressionProtection

Vous consultez la documentation d'Apigee Edge.
Consultez la documentation Apigee X.
en savoir plus

La règle RegularExpressionProtection définit les expressions régulières qui sont évaluées au moment de l'exécution sur les paramètres d'entrée ou les variables de flux. Vous utilisez généralement cette règle afin de vous protéger contre les menaces de contenus, telles que l'injection SQL ou JavaScript, ou pour vérifier les paramètres de requête incorrects tels que les adresses e-mail ou les URL.

Les expressions régulières peuvent être définies pour les chemins de requête, les paramètres de requête, les paramètres de formulaire, les en-têtes, les éléments XML (dans une charge utile XML définie à l'aide de XPath), les attributs d'objet JSON (dans une charge utile JSON définie à l'aide de JSONPath).

L'exemple suivant de règle RegularExpressionProtection protège le backend contre les attaques par injection SQL :

<!-- /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>

Antimodèle

Les quantificateurs par défaut (*, + et ?) sont par nature gourmands en ressource : ils commencent par correspondre à la séquence la plus longue possible. Lorsqu'aucune correspondance n'est trouvée, ils reviennent progressivement pour tenter de correspondre au modèle. Si la chaîne résultante correspondant au modèle est très courte, l'utilisation de quantificateurs gourmands en ressources peut prendre plus de temps que nécessaire. Ceci est particulièrement vrai si la charge utile est importante (en dizaines ou centaines de Ko).

L'exemple d'expression suivant utilise plusieurs instances de .*, qui sont des opérateurs gourmands en ressources :

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

Dans cet exemple, la règle RegularExpressionProtection tente d'abord de faire correspondre la séquence la plus longue possible (la chaîne entière). Si aucune correspondance n'est trouvée, la règle est revient progressivement en arrière. Si la chaîne correspondante est proche du début ou du milieu de la charge utile, l'utilisation d'un quantificateur gourmand en ressources comme .* peut nécessiter beaucoup plus de temps et de puissance de traitement que les qualificatifs réticents tels que .*? ou (moins courants) de quantificateurs progressifs tels que .*+.

Les quantificateurs réticents (tels que X*?, X+?, X??) commencent par tenter de faire correspondre un seul caractère depuis le début de la charge utile, et ajoutent progressivement des caractères. Les quantificateurs réticents (tels que X?+, X*+, X++) tentent de faire correspondre la charge utile complète une seule fois.

Examinez l'exemple de texte suivant pour le modèle ci-dessus :

Hello this is a sample text with Exception in thread
with lot of text after the Exception text.

Utiliser le .* gourmand n'est pas performant dans le cas présent. Le modèle .*Exception in thread.* prend 141 étapes pour correspondre. En utilisant le modèle .*?Exception in thread.* (qui utilise un quantificateur réticent), le résultat ne serait que de 55 étapes.

Impact

L'utilisation de quantificateurs gourmands tels que des caractères génériques (*) avec la règle RegularExpressionProtection peut entraîner :

  • Une augmentation globale de la latence des requêtes API pour une taille de charge utile modérée (jusqu'à 1 Mo)
  • Un délai plus long pour terminer l'exécution de la règle RegularExpressionProtection
  • Les requêtes API comportant des charges utiles volumineuses (> 1 Mo) échouent avec une erreur 504 de délai d'inactivité de la passerelle si le délai d'expiration prédéfini est écoulé sur le routeur périphérique
  • L'utilisation élevée du processeur sur les processeurs de messages en raison de la grande quantité de traitement pouvant impacter également les autres requêtes API

Bonne pratique

  • Évitez d'utiliser des quantificateurs gourmands tels que .* dans les expressions régulières avec la règle RegularExpressionProtection. Utilisez plutôt des quantificateurs réticents tels que .*? ou des quantificateurs possessifs tels que .*+ (plus rarement).

Documentation complémentaire