OVH Cloud OVH Cloud

anti injections

37 réponses
Avatar
N.K. Cole
Bonjour

Que penser de !eregi("(<|\'|\").*(>|\'|\")",$string) comme script de
détection d'injections ?

7 réponses

1 2 3 4
Avatar
N.K. Cole
Toi tu construis ta requete "insert into visiteurs value (12, 42, '$nom')"
pensant que c'est tout bon.
En remplacant $nom, ca donne
insert into visiteurs value (12, 42, 'Machin') ; DELETE from visiteurs
WHERE

('A'='A') et ca te vide ta base


eregi("(<|'|"|().*(>|'|"|))",$string)

filtre tout ce qui est compris entre parenthèses, guillements simples ou
doubles ou crochets ce qui bloque toute insertion de values(..mauvaises
affaires...) de 'x' , "x", <...>. En fait le fait de trouver quoi que ce
soit appartenant a cette règle suffit pour que mon script rejette la source
et donc n'exécute pas le script d'insertion de la ligne dans la table.

if eregi("(<|'|"|().*(>|'|"|))",$string) { echo "Petit malin va";}
else { ..... insert into visiteurs values ( .... $string);}

Oui | Non : j'ai raison ? je n'ai pas raison

Avatar
Vincent Lascaux
eregi("(<|'|"|().*(>|'|"|))",$string)

filtre tout ce qui est compris entre parenthèses, guillements simples ou
doubles ou crochets ce qui bloque toute insertion de values(..mauvaises
affaires...) de 'x' , "x", <...>. En fait le fait de trouver quoi que ce
soit appartenant a cette règle suffit pour que mon script rejette la
source
et donc n'exécute pas le script d'insertion de la ligne dans la table.

if eregi("(<|'|"|().*(>|'|"|))",$string) { echo "Petit malin va";}
else { ..... insert into visiteurs values ( .... $string);}

Oui | Non : j'ai raison ? je n'ai pas raison


Oui, tu as raison : avec ca il n'y a pas trop de risque
Non, tu n'as pas raison de dire "Petit malin va" : ton script filtre trop.
D'Artagnan pourra pas s'inscrire (j'avais choisi ce nom justement parcequ'il
y a une apostrophe dedans).

Les données dans une requête SQL ne sont pas les mêmes que celles qui seront
stockées dans la base ( pour stoquer ' dans la base, il faut faire insert
''' (4 caractères pour représenter une donnée d'1 caractere de long)). Il
faut donc transformer les données avant de créer ta requête SQL.
Ton script élimine les données qui ne marchent pas avec ton algo (qui est
simplement d'entourer la chaine d'apostrophes). Ce n'est pas propre comme
méthode. Il faut plutot changer l'algo. Il y a une fonction qui est là pour
ca : mysql_escape_string, sers-t-en.

--
Vincent

Avatar
N.K. Cole
if eregi("(<|'|"|().*(>|'|"|))",$string) { echo "Petit malin va";}


D'Artagnan pourra pas s'inscrire (j'avais choisi ce nom justement
parcequ'il

y a une apostrophe dedans).


Vrai

Alors si je remplace par
ereg("[<>(=)"$@&!]")

ca devrait permettre à d'Artagnan de s'inscrire.

Je ne crois pas qu'il y ait de requête mysql sans "=" ou "!".
Le "$" et "&" repèrent le passage de variables par référence ou valeur, et
le "@" empèche de supprimer le mode verbal du sgbd.

Pour injecter la bd fautqu'on utilise au moins un de ces caractères.

méthode. Il faut plutot changer l'algo. Il y a une fonction qui est là
pour

ca : mysql_escape_string, sers-t-en.


Cette fonction risque de salir la base de données avec des inscriptions
non-exécutables (ça pourrait être intéressant de les receuillir et en faire
un répertoire ) et je veux éviter cela. Si je ne peux faire autrement c'est
différent. Mais moins de ménage (beurk) à faire c'est toujours mieux non ?

J'ai aussi un algo qui limite le nombre d'espaces ou de "-" ou de "_" dans
un nom ou prénom pour éviter d'hériter de noms du genre :
saleté-de_pouriture de nègre batard

En fait il limite à 3 les prénoms et à 40 la longueur totale.

J'entend filtrer aussi certaines insultes populaires.

A mon âge on devient économe de son temps. Et je préfère de loin peindre que
nettoyer une bd !!


Avatar
Vincent Lascaux
D'Artagnan pourra pas s'inscrire (j'avais choisi ce nom justement
parcequ'il

y a une apostrophe dedans).


Vrai

Alors si je remplace par
ereg("[<>(=)"$@&!]")

ca devrait permettre à d'Artagnan de s'inscrire.


Non, parceque si tu fais "insert into visiteurs values ('$nom')", avec $nom
= "D'Artagnan", ca passera pas...
Il faut faire "insert into visiteurs values
('".mysql_escape_string($nom)."')"

Ensuite, libre à toi de filtrer précédemment et d'indiquer les caractères
que tu veux. Mais ce filtre n'est pas fait pour protéger la base d'une
attaque (juste pour éviter que les gens rentrent n'importe quoi). Dans ce
cas, un filtre qui indique les caractères autorisés me semble plus indiqué
(un nom contient a-z, A-Z, espaces, apostrophes et tirets, ereg("^[a-zA-Z
'-]+$"))

Le "$" et "&" repèrent le passage de variables par référence ou valeur, et


Encore une fois, les variables ne seront PAS interprétées...

méthode. Il faut plutot changer l'algo. Il y a une fonction qui est là
pour

ca : mysql_escape_string, sers-t-en.


Cette fonction risque de salir la base de données avec des inscriptions
non-exécutables (ça pourrait être intéressant de les receuillir et en
faire
un répertoire ) et je veux éviter cela.


C'est quoi des inscriptions non-executables ?
Je vais reexpliquer encore une fois le but de cette fonction : elle
transforme une chaine de caractères pour qu'elle puisse être mise dans une
requête SQL (et quelle soit interprétée avec la bonne valeur par le sgbd).
Exemple : pour que le sgbd comprenne "apostrophe", il faut écrire '. Pour
simplifier, c'est une *faute* de construire une requête SQL avec des chaines
qui ne sont pas passées un moment où à un autre par cette fonction.

Je ne vois pas en quoi celà va salir la base SQL. Si tu fais "insert into
visiteurs values ('".mysql_escape_string($nom)."')", tu sais que dans ta
base de donnée sera stoqué l'exacte contenu de $nom. Si tu fais juste
"insert into visiteurs values ('$nom')", il y a pas mal de chances que ca
marche pas, et dans le cas où ca marche, il y a des chances que ce qu'il y a
dans la base n'est pas ce que l'utilisateur a entré (l'utilisateur entre
D'Artagnan, ca stoque D'Artagnan (ce qui n'est pas ce que l'utilisateur a
entré))

J'entend filtrer aussi certaines insultes populaires.


OK, ca c'est autre chose : tu peux filtrer si tu veux les données avant de
les inserer (pour interdire des noms avec des chiffres dedans par exemple),
mais ca ne te dispense pas de la transformation donnée brute => donnée qu'on
peut mettre dans une requête SQL (transformation réalisée par
mysql_escape_string)

A mon âge on devient économe de son temps.


Et têtue aussi ? :P

--
Vincent


Avatar
N.K. Cole
ereg("[<>(=)"$@&!]")

ca devrait permettre à d'Artagnan de s'inscrire.


Non, parceque si tu fais "insert into visiteurs values ('$nom')", avec
$nom

= "D'Artagnan", ca passera pas...


la regexp identifie les caractères suivants : <>()="$@&!

d'Artagnan n'a aucun caractère qui corresponde à cette liste.

Si un comique inscrit un quelconque de ces caractères dans un champ de
saisie, la regexp l'identifie et ma fonction rejette la saisie.

C'est quoi des inscriptions non-executables ?


N'importe quoi sauf une injection mysql et aussi qui n'a aucun rapport avec
la question posée comme par exemple des insultes ou tout simplement quelque
chose du genre "a;lkdfjpq9ifn p84hkajhgla;"

Je vais reexpliquer encore une fois le but de cette fonction : elle


Pas nécessaire.

Ce que j'ai tenté d'expliquer c'est que mysql_escape_string ne filtre rien
et donc permet de stocker n'importe quoi dans la base de données (insultes
etc) ce que je cherche à éviter avec mon regexp.

La séquence d'utilisation serait :

if (ereg("[<>(=)"$@&!]")) {
afficher une page d'erreurs
}
else {
if (ereg(identification de donnée sans insultes) ) {
$req = "insert into visiteurs mysql_escape_string($nom)" ; exec()
}
}

C'est résumé mais ça montre la séquence partielle parce que, un prénom ne
dépasse pas tellement 13 caractères. Un prénom composé ne comporte pas
vraiment plus de 2 ou 3 prénoms maximum. Donc un regexp qui identifie les
prénoms > 41 caractères de long comprenant plus de 3 prénoms et/ou plus de
1 ou 2 (espace ou tiret ou souligné) est aussi à ajouter.

Au lieu d'utiliser mysql_esc.... en premier lieu et stocker n'importe quoi.
De cette façon, seulement ce qui ressemblerait de près à ce que j'accepte
comme donnée valable pourrait être stocké dans la bd réduisant d'autant les
entrées qui n'ont pas de sens.

Et têtue aussi ? :P


Tu trouves ! :)

Ca doit venir d'un héritage chargé.

Natalia Korèny Cole
Peintre et apprentie programmeure


Avatar
loufoque
N.K. Cole a dit le 25/03/2005 à 20:05:

Je ne crois pas qu'il y ait de requête mysql sans "=" ou "!".
Le "$" et "&" repèrent le passage de variables par référence ou valeur, et
le "@" empèche de supprimer le mode verbal du sgbd.


Oulaaah...
Le contenu des caractères n'est pas évalué en tant que code PHP et
heureusement !
Ces caractères ne présentent absolument aucun risque !

Le seul problème, c'est que ' sert de délimiteur à la chaîne dans la
requête SQL. Si la chaîne PHP contient un ', alors il faut l'échapper
avec le mécanisme du SGBD (généralement on échappe avec , d'autres fois
avec un autre ')


Cette fonction risque de salir la base de données avec des inscriptions
non-exécutables


Hein ? (je ne comprends pas ce que ça veut dire non-exécutables)
Ça (mysql_[real_]escape_string) mettra votre chaîne PHP telle quelle
dans le SGBD. Ça permet de faire la correspondance entre les variables
PHP et celles SQL. (PS: mysql_real_escape_string prend en compte le
charset de la connexion. À priori, ce n'est pas utile qu'avec un charset
non compatible ASCII)
Pour ne pas avoir de problème avec cette correspondance moi je conseille
d'utiliser une fonction "intelligente" qui détecte le type et/ou force
une conversion selon une marque définie (?, %s, %d)...

Avatar
Vincent Lascaux
La séquence d'utilisation serait :

if (ereg("[<>(=)"$@&!]")) {
afficher une page d'erreurs
}
else {
if (ereg(identification de donnée sans insultes) ) {
$req = "insert into visiteurs mysql_escape_string($nom)" ; exec()
}
}


D'accord, ca me semble bon: tu filtres les données brutes pour vérifier
qu'elles correspondent bien à ce que tu attends, et ensuite tu inseres en
utilisant mysql_escape_string.
Au passage, c'est $req = "insert into visiteurs
('".mysql_escape_string($nom)."')" (il n'y a pas de raison pour que PHP
aille executer la fonction mysql_escape_string à l'interieur de la chaine de
caracteres).

--
Vincent

1 2 3 4