Problèmes de déni de service
La préoccupation la plus courante avec les expressions rationnelles est une attaque par déni de service via des schémas pathologiques qui deviennent exponentiels - voire super-exponentiels! - et semblent donc prendre une éternité à résoudre. Celles-ci ne peuvent apparaître que sur des données d'entrée particulières, mais on peut généralement en créer une dans laquelle cela n'a pas d'importance.
Ceux-ci dépendront quelque peu de l'intelligence du compilateur regex que vous utilisez, car certains d'entre eux peuvent être détectés pendant la compilation. Les compilateurs Regex qui implémentent la récursivité ont généralement un compteur de profondeur de récursivité intégré pour vérifier la non-progression.
L'excellent article de Russ Cox de 2007 sur la correspondance d'expressions régulières peut être simple et rapide (mais lent en Java, Perl, PHP, Python, Ruby, ...) parle des façons dont la plupart des NFA modernes, qui semblent tous dériver du code de Henry Spencer , souffrent d'une grave dégradation des performances, mais là où un NFA de style Thompson ne rencontre pas de tels problèmes.
Si vous n'admettez que des modèles qui peuvent être résolus par les DFA, vous pouvez les compiler en tant que tels, et ils s'exécuteront plus rapidement, voire beaucoup plus rapidement. Cependant, cela prend du temps . Le document de Cox mentionne cette approche et ses problèmes associés. Tout se résume à un compromis temps-espace classique.
Avec un DFA, vous passez plus de temps à le construire (et à allouer plus d'états), alors qu'avec un NFA, vous passez plus de temps à l'exécuter, car il peut s'agir de plusieurs états en même temps, et le retour en arrière peut manger votre déjeuner - et votre processeur.
Solutions de déni de service
La façon la plus raisonnable d'aborder ces modèles qui sont sur le côté perdant d'une course avec la mort par la chaleur de l'univers est de les envelopper avec une minuterie qui place effectivement un temps maximum alloué à leur exécution. Habituellement, ce sera beaucoup, beaucoup moins que le délai d'expiration par défaut fourni par la plupart des serveurs HTTP.
Il existe différentes façons de les implémenter, allant d'une forme simple alarm(N)
au niveau C, à une sorte de try {}
blocage des exceptions de type alarme de capture, jusqu'à la création d'un nouveau thread spécialement créé avec une contrainte de synchronisation intégrée.
Légendes de code
Dans les langages regex qui admettent les appels de code, un mécanisme pour autoriser ou interdire ceux-ci de la chaîne que vous allez compiler doit être fourni. Même si les légendes de code ne servent qu'à coder dans la langue que vous utilisez, vous devez les restreindre; ils n'ont pas besoin d'appeler du code externe, mais s'ils le peuvent, vous avez des problèmes beaucoup plus importants.
Par exemple, en Perl, on ne peut pas avoir d'appels de code dans les expressions régulières créées à partir d'une interpolation de chaîne (comme ce serait le cas, comme ils sont compilés pendant l'exécution) à moins que le pragma spécial à portée lexique soit use re "eval";
actif dans la portée actuelle.
De cette façon, personne ne peut se faufiler dans une légende de code pour exécuter des programmes système comme rm -rf *
, par exemple. Parce que les légendes de code sont si sensibles à la sécurité, Perl les désactive par défaut sur toutes les chaînes interpolées, et vous devez faire tout votre possible pour les réactiver.
Défini par l'utilisateur \ P {roperties}
Il reste une question plus sensible à la sécurité liée aux propriétés de style Unicode - comme \pM
, \p{Pd}
, \p{Pattern_Syntax}
ou \p{Script=Greek}
- qui peuvent exister dans certains compilateurs regex que le soutien que la notation.
Le problème est que dans certains d'entre eux, l'ensemble des propriétés possibles est extensible par l'utilisateur. Cela signifie que vous pouvez avoir des propriétés personnalisées qui sont de véritables appels de code vers des fonctions nommées dans un espace de nom particulier, comme \p{GoodChars}
ou \p{Class::Good_Characters}
. La façon dont votre langue gère ces problèmes pourrait valoir la peine d'être examinée.
Bac à sable
En Perl, un compartiment sandbox via le Safe
module donnerait le contrôle sur la visibilité de l'espace de noms. D'autres langages proposent des technologies de sandboxing similaires. Si de tels périphériques sont disponibles, vous voudrez peut-être les examiner, car ils sont spécifiquement conçus pour une exécution limitée de code non approuvé.