OVH Cloud OVH Cloud

Controle des donnees entrees

28 réponses
Avatar
Pascale
Bon, j'essaye une autre question...

Je travaille sur un site où des utilisateurs peuvent entrer des textes via
des formulaires.
Toutes les pages sont en iso-8859-15. Une fois contrôlées et validées, ces
données sont entrées dans diverses tables MySQL en UTF-8 Unicode.
Évidemment, faudrait pas qu'un utilisateur, par volonté de nuire ou par
ignorance, puisse entrer des données dangereuses...
Je suis allée voir la FAQ et j'ai recherché dans les archives, ce qui m'a
amenée à cette discussion : http://tinyurl.com/y4qycc et à la page
http://www.miakinen.net/vrac/charsets/

J'ai donc essayé d'appliquer les conseils donnés :
$ok = preg_match("|^([- @!%&()/*+?;:.0-9A-Za-z]|\xE2\x82\xAC|\xC2[\xA0-
\xBF]|\xC3[\x80-\xBF])*$|",$string);

Mais je me fais jeter à partir de xE2 :

Warning: preg_match(): Unknown modifier 'â'

En fait, tous les caractères codés en hexa sont rejetés.
Est-ce normal ?

Comment faut-il faire le test pour autoriser presque tout (sauf ce qui
pourrait être dangereux) :
- les caractères alphanumériques, y compris accentués, minuscules et
majuscules, cédilles en minuscule et majuscule
- les signes de ponctuation, apostrophes comprises, et si possible les
guillemets doubles
- quelques caractères spéciaux : &,@,/, symboles monétaires, parenthèses,
crochets, vrais guillements «», espaces insécables, si possible les ½, æ...

Bref, faut-il/peut-on les lister directement les caractères et écrire par
exemple (j'abrège) :

$masque="^([- @!%&()/*+?;:._&'"0-9A-Za-zéèêëçÇàâäùÉÈÊË])*$";

Ou y a-t-il un moyen plus adapté, plus pratique ?

--
Pascale

10 réponses

1 2 3
Avatar
Olivier Miakinen

[...]
Toutes les pages sont en iso-8859-15. Une fois contrôlées et validées, ces
données sont entrées dans diverses tables MySQL en UTF-8 Unicode.
Évidemment, faudrait pas qu'un utilisateur, par volonté de nuire ou par
ignorance, puisse entrer des données dangereuses...
Je suis allée voir la FAQ et j'ai recherché dans les archives, ce qui m'a
amenée à cette discussion : http://tinyurl.com/y4qycc


Tiens, c'est un de mes articles, ça.

et à la page http://www.miakinen.net/vrac/charsets/


Pas de doute, c'est à moi aussi. ;-)

J'ai donc essayé d'appliquer les conseils donnés :
$ok = preg_match("|^([- @!%&()/*+?;:.0-9A-Za-z]|xE2x82xAC|xC2[xA0-
xBF]|xC3[x80-xBF])*$|",$string);

Mais je me fais jeter à partir de xE2 :


Tiens, ça m'apprendra à tester mes bouts de code avant de les jeter en
pâture aux lecteurs et lectrices de fclp !

Warning: preg_match(): Unknown modifier 'â'


Et c'est là qu'il est parfois utile de lire le manuel en anglais plutôt
qu'en français, pour voir que ce qui s'appelle « option » en français
est nommé « modifier » en anglais :
http://fr2.php.net/manual/fr/reference.pcre.pattern.modifiers.php
http://fr2.php.net/manual/en/reference.pcre.pattern.modifiers.php

Le problème, c'est que j'avais choisi le « | » comme délimiteur plutôt
que le « / », ce qui marchait bien pour [- @!%&()/*+?;:.0-9A-Za-z] mais
qui coince dès le « | » d'alternative qui suit. Du coup, le caractère
suivant est considéré comme une option ([en] modifier) et ça foire.

Note que le caractère suivant n'est pas xE2x82xAC (¤ en UTF-8) mais
xE2 (â en iso-8859-15) puisque tu dis toi-même que tes pages sont en
iso-8859-15. Ce n'était pas le cas de ma réponse à Phil P. en avril 2006
puisque je supposais UTF-8.

En fait, tous les caractères codés en hexa sont rejetés.
Est-ce normal ?


Ça l'est doublement, à cause de mon erreur et du fait que ma réponse
n'était pas adaptée à ton charset.

Comment faut-il faire le test pour autoriser presque tout (sauf ce qui
pourrait être dangereux) :
- les caractères alphanumériques, y compris accentués, minuscules et
majuscules, cédilles en minuscule et majuscule
- les signes de ponctuation, apostrophes comprises, et si possible les
guillemets doubles


Pour accepter à la fois les pattes de mouches simples et doubles
(« ' » et « " ») il doit falloir faire un traitement particulier
avant insertions dans la base, traitement dont je préfère ne rien
dire car c'est en dehors de mes compétences. Je laisse d'autres te
répondre.

- quelques caractères spéciaux : &,@,/, symboles monétaires, parenthèses,
crochets, vrais guillements «», espaces insécables, si possible les ½, æ...


Tu es en iso-8859-15, donc les seuls caractères que tu pourras recevoir
sont ceux de le table correspondante. Tu auras donc les « $ », « ¢ »,
« £ », « ¤ », « ¥ », « ½ » et « æ » sans aucun problème, ainsi que les
guillemets. En ce qui concerne l'espace insécable, tu peux l'accepter
mais il n'est pas dit que le visiteur saura la générer : certains
navigateurs la remplacent par une espace simple.

Bref, faut-il/peut-on les lister directement les caractères et écrire par
exemple (j'abrège) :

$masque="^([- @!%&()/*+?;:._&'"0-9A-Za-zéèêëçÇàâäùÉÈÊË])*$";

Ou y a-t-il un moyen plus adapté, plus pratique ?


Si tu veux accepter toute la partie haute d'iso-8859-15, tu peux même
utiliser des plages de caractères, par exemple À-ÿ pour toutes les
lettres accentuées majuscules et minuscules plus × et ÷, ou xA0-ÿ
pour la totalité de la partie haute de la table. Note que, si tu as un
éditeur de texte qui ne te remplace pas l'espace insécable par une
espace simple, tu peux directement saisir cette espace insécable plutôt
que xA0. Inversement tu peux préférer xFF à ÿ si ça te semble plus
lisible.

Par ailleurs, puisque il n'y a plus de « | » intempestif, ceci devrait
marcher :
$ok = preg_match("|^[- @!%&()/*+?;:.0-9A-Za-zxA0-xFF]*$|",
$string);

Il y manque quelques uns des caractères que tu souhaitais. Je vais faire
une deuxième réponse séparée pour ça.

Avatar
Olivier Miakinen
Voici donc ma deuxième réponse.


Comment faut-il faire le test pour autoriser presque tout (sauf ce qui
pourrait être dangereux) :
- les caractères alphanumériques, y compris accentués, minuscules et
majuscules, cédilles en minuscule et majuscule


numériques : 0-9
majuscules non accentuées : A-Z
minuscules non accentuées : a-z
majuscules accentuées plus Æ Ç × ß mais sans ¦ ´ ¼ ¾ : xC0-xDF
minuscules accentuées plus æ ç ÷ mais sans ¨ ¸ ½ : xE0-xFF
tous caractères accentués et d'autres trucs sans danger : xA0-xFF


- les signes de ponctuation, apostrophes comprises, et si possible les
guillemets doubles


signes de ponctuation : !,.:;?
éventuellement aussi : ()-/[]
apostrophes : '
guillemets doubles : " (c'est là je pense qu'est le plus gros problème)

- quelques caractères spéciaux : &,@,/, symboles monétaires, parenthèses,
crochets, vrais guillements «», espaces insécables, si possible les ½, æ...


symboles spéciaux : &@/
symboles monétaires : $ plus ceux qui sont déjà dans xA0-xFF
parenthèses, crochets : ()[]
vrais guillemets : sont déja dans xA0-xFF, de même que l'espace
insécable et les ½ æ ¼ Æ.
Il ne faut pas oublier non plus l'espace normale.

Bref, faut-il/peut-on les lister directement les caractères et écrire par
exemple (j'abrège) :

$masque="^([- @!%&()/*+?;:._&'"0-9A-Za-zéèêëçÇàâäùÉÈÊË])*$";

Ou y a-t-il un moyen plus adapté, plus pratique ?


Si tu n'avais pas besoin des ' et " j'aurais proposé :
"|^[] !$&(),./0-9:;?@A-Z[a-zxA0-xFF-]*$|"
Note à quel endroit j'ai mis le ] (au début pour qu'il ne ferme pas la
syntaxe [...]) et le - (à la fin pour que ce ne soit pas une série de
caractères consécutifs).

Mais puisque tu en as besoin, je dirais :
"/^[x20-x7ExA0-xFF]*$/"
... avec un traitement particulier pour les ' et ".

Avatar
Vincent Lascaux
Évidemment, faudrait pas qu'un utilisateur, par volonté de nuire ou par
ignorance, puisse entrer des données dangereuses...


C'est pas ton boulot mais celui de mysql_real_escape_string de faire ca il
me semble (ou alors j'ai loupé la motivation)

--
Vincent

Avatar
Pascale
Olivier Miakinen <om+ écrivait
news:45775ecb$:

Si tu n'avais pas besoin des ' et " j'aurais proposé :
"|^[] !$&(),./0-9:;?@A-Z[a-zxA0-xFF-]*$|"
Note à quel endroit j'ai mis le ] (au début pour qu'il ne ferme pas la
syntaxe [...]) et le - (à la fin pour que ce ne soit pas une série de
caractères consécutifs).

Mais puisque tu en as besoin, je dirais :
"/^[x20-x7ExA0-xFF]*$/"
... avec un traitement particulier pour les ' et ".


Merci Olivier pour ces deux réponses très complètes que je m'en vas
éplucher (o;

Pour ce qui est des guillemets "", je peux difficilement les interdire dans
tous les champs (ou alors les transformer systématiquement en «» ?). Les
guillemets simples '' ne sont pas utiles dans le site en question et je
peux très bien interdire leur emploi (mais dans un autre site, sur lequel
je bosserai dans quelques temps, je pourrai à la rigueur interdire les
guillemets doubles mais pas les simples, car c'est un site botanique, et
ces guillemets simples servent à encadrer les noms de cultivars. Par par
exemple Cistus salviifolius 'Villeveyrac'). Sans compter que ce guillemet
simple (27 en hexa), c'est aussi l'apostrophe, donc je ne vois pas comment
l'interdire?

--
Pascale

Avatar
Pascale
Vincent Lascaux écrivait
news:4577b246$0$4203$:

Évidemment, faudrait pas qu'un utilisateur, par volonté de nuire ou
par ignorance, puisse entrer des données dangereuses...


C'est pas ton boulot mais celui de mysql_real_escape_string de faire
ca il me semble (ou alors j'ai loupé la motivation)


J'ignorais tout de cette fonction, merci Vincent : d'après l'aide PHP,
elle est indispensable ! Il suffirait donc d'utiliser cette fonction au
moment de l'insertion ou de la modification de données dans les tables SQL
pour se débarrasser des problèmes de ' et de " ?
J'ai jeté un coup d'½il à la configuration PHP chez notre hébergeur. Je
lis :

magic_quotes_gpc On On (local value et master value)
magic_quotes_runtime Off Off "
magic_quotes_sybase Off Off "

Faut-il changer quelque chose ou pas ?

Au juste, quels sont les caractères dangereux, ceux qu'ils faut interdire
dans un formulaire ? < et >, il me semble... et quoi d'autre ? Est-ce
vraiment une mauvaise idée d'interdire certains caractères plutôt que de
lister ceux qui sont autorisés dans le texte « tout venant » (sachant qu'il
existe déjà des contrôles spécifiques pour les adresses courriel, les mots
de passe, les URL) ?

--
Pascale


Avatar
John GALLET
Bonjour,

Il suffirait donc d'utiliser cette fonction au
moment de l'insertion ou de la modification de données dans les tables SQL
pour se débarrasser des problèmes de ' et de " ?


C'est exactement le type de fonctions qui souligne le genre de problèmes
qu'on a quand on gère des listes de choses interdites.

Au juste, quels sont les caractères dangereux, ceux qu'ils faut interdire
dans un formulaire ? < et >, il me semble... et quoi d'autre ?


Tout ce qui est dangereux... euh, oui mais comment on le trouve ? La liste
des choses autorisées parce que j'en ai besoin, ça je sais faire. La liste
de toutes les âneries possibles et (in)imaginables que l'on va balancer
dans la truffe de mes scripts, je n'en ai pas la moindre idée. Il y a des
gens très inventifs.

Est-ce vraiment une mauvaise idée d'interdire certains caractères plutôt que de
lister ceux qui sont autorisés


Oui, toujours une mauvaise idée. Même si parfois on s'en contente très
bien si on est conscient de ce qu'on fait.

Reprenons deux cas donc, < et > d'un côté, " et ' de l'autre.

La raison pour laquelle on interdit les deux premiers < et > c'est pour
désamorcer les XSS. Pour le moment, aucun navigateur n'est capable de
transformer &ltBODY ONLOAD=hackme_javascript()&gt; en un équivalent
exécutable et donc transformer < et > en leurs entités html suffit. Pour
le moment. Mais on peut avoir le même genre de gags que ce dessous en
attente.

La raison pour laquelle on échappe " et/ou ' (ça dépend de comment on
écrit son SQL) est double. Déjà pour que ça marche: quand je veux insérer
comme $nom="d'Artagnan"; il faut bien que INSERT...('$nom') ne devienne
pas ...('d'Artagan') // SQL ERROR mais bien ...('d''Artagan') ou
...('d''Artagan') // DEUX ' sous sybase par exemple).

Ensuite parce que dansles attaques possibles, il y a les injections SQL
sur les strings, et que si on échappe pas correctement ces caractères on
va ouvrir une faille. Mais si on travaille dans un charset "normal" comme
latin-1, on en a RIEN A F... de mysql_real_escape_string, un simple
addslashes suffit (ce qui est justement fait par défaut avec
magic_quotes_gpc). En revanche, si le charset de la table sur laquelle on
travaille accepte de traduire le code ascii de ' en sa valeur, comme
addslashes ne verra rien mais que la base traduira, la faille est toujours
présente si se contente de addslashes, qui en fait ne fait qu'établir ne
liste de caractères interdits.

Moralité : bien se poser la question de l'intérêt réel de s'emmerder à
jouer avec utf-8 au lieu de rester en charset usuel. D'ailleurs, et-ce
même logique ? A quoi servent les entités html comme &eacute; ou &agrave;
? N'oublions pas que HTML fonctionne parfaitement ***en ASCII 7 BITS !***
C'est **FAIT POUR**.

a++;
JG

Avatar
Pascale
John GALLET écrivait
news::

Moralité : bien se poser la question de l'intérêt réel de s'emmerder à
jouer avec utf-8 au lieu de rester en charset usuel. D'ailleurs, et-ce
même logique ? A quoi servent les entités html comme &eacute; ou &agrave;
? N'oublions pas que HTML fonctionne parfaitement ***en ASCII 7 BITS !***
C'est **FAIT POUR**.


Merci pour les explications très claires. Seul le dernier paragraphe est
moins clair pour moi...
Nos pages sont en ISO 8859-15 mais à ma connaissance, chez notre hébergeur,
les tables sont en UTF8... quoique, je lis : Interclassement :
latin1_swedish_ci (ce swedish nous a toujous paru bizarre, mais on a déjà
essayé de le changer et déclenché je ne sais plus quelle cata). Il n'est
pas exclu que je confonde tout et n'importe quoi, mais dans ces histoires
de charsets, une chatte n'y retrouverait pas ses petits.

--
Pascale

Avatar
John GALLET
Nos pages sont en ISO 8859-15
Alors arrêtez de vous emmerder avec de l'utf-8.


mais à ma connaissance, chez notre hébergeur,
les tables sont en UTF8


Elles sont en ce que vous leurs dites d'être lors du create table (ou du
create database/création d'instance, selon le SGBDR).

... quoique, je lis : Interclassement : latin1_swedish_ci


Alors ça c'est encore un autre problème et une autre connerie "made in
mysql" (ou "comment emmerder la terre entière par défaut").

essayé de le changer et déclenché je ne sais plus quelle cata). Il n'est
pas exclu que je confonde tout et n'importe quoi,


Il y a trois acteurs, et donc autant de charsets acceptés possibles : le
navigateur, le middle-tiers (php) et le sgbdr (mysql). Si le middle-tiers
(php) n'assure pas la cohérence entre les trois, c'est la foire du
Trône avec Barbes à Papa (ou du ronron-croquette si on préfère). Le seul
problème si on colle tout le monde en entités html asci 7 bits et qu'on
arrête de s'emmerder c'est que l'ordre des résultats est faussé et que les
zones de stockage doivent être prévues beaucoup plus grandes. Donc de
manière générale, on préfère stocker "é" quand on le reçoit plutôt que
&eacute;.

mais dans ces histoires de charsets, une chatte n'y retrouverait pas ses
petits.
Meow.

Vu le bazar que ça met, j'irai même jusqu'à dire qu'une mère truie n'y
retrouverait pas ses petits gorets non plus.

a++;
JG

Avatar
Pascale
John GALLET écrivait
news::

Meow.
Vu le bazar que ça met, j'irai même jusqu'à dire qu'une mère truie n'y
retrouverait pas ses petits gorets non plus.


Même conclusion...

Tiens, encore un truc que je ne m'explique pas, mais là, peut-être que la
solution est plus simple :
J'ai un beau formulaire à moi, avec de beaux champs en input type="text"
name="nom" etc.
Je rentre dans de ces très beaux champs du formulaire :

C'est mon "gros" chien Rocky

Je visualise dans un beau tableau le contenu de mon formulaire, je lis
bien : C'est mon "gros" chien Rocky. Avant d'afficher le contenu des
données entrées dans le formulaire, j'ai écrit
$_SESSION['nom']=$_POST['nom']. Je clique donc sur mon beau bouton
Corriger, qui me ramène au formulaire précédent en affichant dans le champ
texte le contenu de ma valeur de session.
Et là, horreur et malédiction, je lis : C'est mon . Tout ce qui est à
partir du " a disparu corps et bien.

Par contre, si je remplace dans le formulaire mon input type="text" par un
textarea name="nom", je peux mettre tous les guillemets que je veux, je
n'ai plus de problème d'affichage (et l'insertion des données dans la base
SQL est sans problème elle aussi).
D'une part, ça m'embête un peu de remplacer mes input type="text" par des
textarea (je trouve ça assez moche, même en ne mettant qu'une ligne), mais
en plus, j'aimerais comprendre pourquoi le fait de changer le type
d'élément de formulaire change quelque chose à la prise en charge des
guillemets.

--
Pascale

Avatar
John GALLET
J'ai un beau formulaire à moi, avec de beaux champs en input type="text"
name="nom" etc.
Oui mais la cause est dans le etc. Il y a aussi VALUE

C'est mon "gros" chien Rocky
Et là, horreur et malédiction, je lis : C'est mon . Tout ce qui est à
partir du " a disparu corps et bien.


Ca dépend de ce qu'on regarde. Dans le navigateur, au mieux il y a ce
début de texte, sans erreurs par la suite, au pire il y a des décalages
incompréhensibles partour après. Il y a fort à parier que si on regarde
le HTML on verra :

<INPUT TYPE="text" NAME="nom" VALUE="C'est mon "gros" chien Rocky">

...et plouf les ". Si tu mets tes attributs entre ", il faut échapper les
" en les renvoyant, idem pour des attributs entre ' (les deux sont
autorisés si ma mémoire défaillante et la lecture des RFCs ad hoc par mon
collègue et ami le Dr Watson.. euh non flûte, Olivier M., sont correctes).

Par contre, si je remplace dans le formulaire mon input type="text" par un
textarea name="nom", je peux mettre tous les guillemets que je veux, je
n'ai plus de problème d'affichage
Logique, car alors le nom n'est plus dans un attribut entouré de ".


en plus, j'aimerais comprendre pourquoi le fait de changer le type
d'élément de formulaire change quelque chose à la prise en charge des
guillemets.


Il suffit de regarder le code HTML résultant.

a++
JG

1 2 3