PCRE & sécurité

Eléphanteau du PHP | 18 Messages

27 juin 2007, 02:37

Bonjour,

J'aurais deux questions à propos des PCRE...

1) Est-ce qu'il existe une liste exhaustive des marqueurs supportés par pcre pour encadrer les regex ?

2) Quelles sont les sécurités à prendre si on veut permettre l'utilisation de regexes par les utilisateurs via une interface quelconque ? Plus précisément si on veut leur permettre de renseigner les trois premiers attributs de preg_replace (la regex, son remplacement, et la chaine de caractères à laquelle on applique les changements) ; je pense notamment à l'option e qui permet d'exécuter n'importe quelle fonction php, ce qui est très risqué.

Merci pour votre attention.
Modifié en dernier par o7a.net le 26 déc. 2008, 16:16, modifié 1 fois.

Eléphanteau du PHP | 11 Messages

12 juil. 2007, 14:39

J'avais pas vu ce sujet.
Un article qui devrait t'intéresser.

Eléphanteau du PHP | 18 Messages

13 juil. 2007, 14:18

Autrement dit l'article dit qu'il est impossible de permettre l'insertion de regexes par les utilisateurs sans failles de sécurité...

preg_quote ne convient pas puisque sans les caractères spéciaux, l'insertion de regexes perd tout son intérêt...

Créer son propre langage ... ça ne me fait pas peur mais il ne sera dans tous les cas pas aussi complet que PCRE, et rien ne dit que ce langage ne laissera pas lui aussi des failles de sécurité (surtout si je ne sais même pas quelles sont les failles de PCRE).

Ce que j'aimerais savoir, c'est outre l'option e, quelles peuvent être ces failles ? ... à l'exception des erreurs dans l'interprétation de la regex (erreurs de syntaxe, boucles infinies ...) qui, cela dit, peuvent être gérées sans poser de problèmes de sécurité ...

merci pour ton aide Mandar.
Modifié en dernier par o7a.net le 26 déc. 2008, 16:17, modifié 1 fois.

ViPHP
ViPHP | 1380 Messages

14 juil. 2007, 14:11

Hello,

1) Tout caractère non alphanum à l'exception du backslash. Plus, assez curieusement, les caractères ouvrant/fermant tels que [{(<. C'est une curiosité PHP car je ne connais aucun autre language qui les accepte comme délimiteur. Ainsi les masques suivants sont corrects:
  • Délimiteurs classiques
    /masque/
    #masque#
    `masque`
    !masque!
    .masque.
    %masque%
  • Délimiteurs exotiques (pas recommandé car difficilement lisible pour tout esprit "regex" normalement constitué!)
    [masque]
    <masque>
    (masque)
    {masque}
2) Option e: préférer de loin preg_replace_callback(), plus lisible et performante.
ripat

Eléphanteau du PHP | 18 Messages

14 juil. 2007, 15:43

Voilà qui est clair, pour les marqueurs, merci pour l'info.

Pour l'option e et callback, je cherche justement à me débarrasser de l'insertion de php puisque je dois permettre aux utilisateurs d'entrer eux même les regexes.

ViPHP
ViPHP | 1380 Messages

14 juil. 2007, 18:23

Pour l'option e et callback, je cherche justement à me débarrasser de l'insertion de php puisque je dois permettre aux utilisateurs d'entrer eux même les regexes.
Le problème de preg_replace() avec l'option e est que le replacement string est évalué comme du code PHP ---> DANGER!
e force preg_replace() à traiter replacement comme du code PHP une fois que les substitutions adéquates ont été faites.
Alors qu'avec preg_replace_callback(), le replacement string est traité classiquement par le moteur regex sans évaluation par PHP. Les captures sont envoyées vers la fonction en callback où elles seront traitées selon les besoins, à nouveau sans évaluation de code PHP.

De plus, preg_replace() option e est totalement illisible (la valse des guillemets!).
// L'exemple de la doc:

preg_replace("/(<\/?)(\w+)([^>]*>)/e",
              "'\\1'.strtoupper('\\2').'\\3'",
              $html_body);

// avec preg_replace_callback

function maFonction ($capture) {
  return $capture[1] . strtoupper($capture[2]) . $capture[3];
}

preg_replace_callback("/(<\/?)(\w+)([^>]*>)/",
              'maFonction',
              $html_body);

Un peu plus verbeux mais tellement plus simple et plus sécuritaire. Et beaucoup plus rapide.
ripat

Eléphanteau du PHP | 18 Messages

14 juil. 2007, 21:58

inutile d'argumenter pour preg_replace_callback, je suis totalement convaincu de ses avantages devant l'option e de preg_replace !

En fait, ce que je souhaite faire, c'est permettre aux utilisateurs de donner la regex, le replacement string, et la chaine de caractères à laquelle on applique les modifications (puis le résultat leur est renvoyé).

J'utilise donc preg_replace, et je disais que la première chose que j'ai fait, c'est d'empêcher l'utilisation de l'option e (qui permettrait aux utilisateurs d'exécuter n'importe quelle action en php). Seulement j'aimerai savoir s'il n'y a pas d'autres options (ou je ne sais quoi) qui permettraient à des utilisateurs malveillants (ou maladroits) de causer des quelconques problèmes autres que les erreurs d'interprétation de la regex qu'ils ont écrit...

D'après la doc de php.net, je ne vois rien d'autre que l'option e, mais pour m'en assurer j'aimerai votre avis.

ViPHP
ViPHP | 1380 Messages

15 juil. 2007, 10:08

preg_replace_callback() est sûre en soi. Tout va dépendre de ton code en amont ou en aval

Pour le reste de ton code, précautions habituelles contre les injections classiques:
  • injections SQL
  • mail header (fonction mail())
  • eval() exec() passthru() et compagnie (injection shell)
  • preg_replace option e
  • $_GET $_POST non validés
  • include() et require()
  • ...
ripat

Administrateur PHPfrance
Administrateur PHPfrance | 3131 Messages

15 juil. 2007, 12:08

J'utilise donc preg_replace, et je disais que la première chose que j'ai fait, c'est d'empêcher l'utilisation de l'option e (qui permettrait aux utilisateurs d'exécuter n'importe quelle action en php). Seulement j'aimerai savoir s'il n'y a pas d'autres options (ou je ne sais quoi) qui permettraient à des utilisateurs malveillants (ou maladroits) de causer des quelconques problèmes autres que les erreurs d'interprétation de la regex qu'ils ont écrit...
En sécurité la première règle c'est «tout interdire, et autoriser au cas par cas».
Donc plutôt que de te poser la question de «quelles options pourraient poser problème ?» demande-toi plutôt quelles options ne peuvent pas en poser, et n'autoriser que celles-là.

Pour le masque en lui-même, toujours le même raisonnement : je ne laisserais pas l'utilisateur entrer son propre délimiteur. Cela évite d'avoir à se demander quel délimiteur risque de poser problème. J'en fixe un, et l'utilisateur s'y conforme.

Ainsi l'entrée du masque se ferait avec deux champs :

Code : Tout sélectionner

/ [ . . . ] / [ . . . ]
L'utilisateur entre son masque, sans les délimiteurs (qui sont fixés à '/') dans le premier champ, et ses options dans le deuxième champ.
Si tu n'as décidé d'autoriser que les options 's', 'i', et 'm', alors tout ce qui n'est pas 's', 'i', ou 'm' sera simplement ignoré ou sera la cause de l'affichage d'un message d'erreur.