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
Pascale
John GALLET écrivait
news::

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

Value="$monbeautexte" exact ! J'aurais dû y penser...


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,


Oui.

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">


Pile poil (c'est la cas de dire en parlant du chien...

...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).


Merci, Sherlock (:

Logique, car alors le nom n'est plus dans un attribut entouré de ".


Ben voilà, j'ai enfin pigé...

En fait, j'avais pas pensé jusque là à cette histoire de guillemets car
j'utilise en principe des « »... Il était temps que je revienne sur terre,
la plupart des gens utilisent des " ".

--
Pascale


Avatar
Pascale
John GALLET écrivait
news::

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).


Avant de tout passer en textarea j'ai essayé de faire ceci :

Formulaire (aucun changement) :

<input type="text" name="nomplante" size="50" maxlength="50" style="...;"
value="'.stripslashes($_SESSION['nomplante']).'">

Programme qui suit l'envoi du formulaire (test du contenu avec renvoi le
cas échéant au formulaire, affichage qui récapitule l'ensemble des données
entrées par l'utilisateur, possibilité de valider, de modifier,
d'abandonner). Je rajoute un addslashes qui n'y était pas :

$_SESSION['nomplante']­dslashes($_POST['nomplante']);

Si je saisis dans le formulaire :
C'est un très "gros" chien Rocky
puis si je clique sur Visualiser, et si je reviens sur le formulaire, je
lis :

C'est un très

(dans le code je lis : value="C'est un très "gros" chien" )

Donc je crois que je ne vais pas me compliquer la vie, je vais passer mes
zones de saisie en textarea. L'inconvénient est que je ne peux pas limiter
le nombre de caractères saisis (je suis obligée de tronquer a posteriori),
sauf à utiliser un Javascript de décompte de caractères, ce qui ne
m'enthousiasme pas, trop compliqué à piger pour mon petit cerveau... et
j'aime bien comprendre ce que je fais (-:

--
Pascale

Avatar
John GALLET
Si tu mets tes attributs entre ", il faut échapper les
" en les renvoyant,
Miardidiou, mauvais terme: pas échapper, traduire, transcoder.



(dans le code je lis : value="C'est un très "gros" chien" )


Oui mais non, ce qu'il faut c'est transformer " en &quot; et pas en " le
terme "échapper" que j'ai employé est impropre.

De manière générale, de toutes façons, on a intérêt à htmliser tout ce
qu'on renvoie au navigateur, tant pour raisons de compatibilité que
mesure anti-xss basique.

JG


Avatar
Olivier Miakinen
Le 13/12/2006 17:49, Pascale a (presque) écrit (je simplifie) :

'<input type="text" value="'.stripslashes($value).'">'

[...]

(dans le code je lis : value="C'est un très "gros" chien" )


peut-être :

'<input type="text" value="'.str_replace('"', '"', $value).'">'

ou :

"<input type='text' value='".str_replace("'", "'", $value)."'>"

voire :

$value = str_replace("'", "'", $value);
"<input type='text' value='$value'>"

Avatar
Pascale
John GALLET écrivait
news::

Oui mais non, ce qu'il faut c'est transformer " en &quot; et pas en "
le terme "échapper" que j'ai employé est impropre.


D'accord, je pige.

De manière générale, de toutes façons, on a intérêt à htmliser tout ce
qu'on renvoie au navigateur, tant pour raisons de compatibilité que
mesure anti-xss basique.


Donc pas mal de caractères là encore : espaces insécables, caractères
accentués, ç et plein d'autres auxquels je ne pense pas forcément... Par
contre, je n'aimerais pas que les utilisateurs voient ces caractères à
l'écran lorsqu'ils reviennent sur leur formulaire (pour modifier) et je ne
voudrais pas que dans un champ où ils peuvent entrer, disons, 20
caractères, ils ne puissent en fait en entrer que 12 ou 15.
Plus j'apprends de choses, plus je vois l'étendue de ce qui me reste à
apprendre (:

--
Pascale

Avatar
Pascale
Olivier Miakinen <om+ écrivait
news:4580329d$:

peut-être :

'<input type="text" value="'.str_replace('"', '"', $value).'">'

ou :

"<input type='text' value='".str_replace("'", "'", $value)."'>"

voire :

$value = str_replace("'", "'", $value);
"<input type='text' value='$value'>"


Je vais essayer de tester ces différentes solutions, merci : j'ai
l'embarras du choix (:
--
Pascale

Avatar
John GALLET
De manière générale, de toutes façons, on a intérêt à htmliser tout ce
qu'on renvoie au navigateur, tant pour raisons de compatibilité que
mesure anti-xss basique.


Donc pas mal de caractères là encore : espaces insécables, caractères
accentués, ç et plein d'autres auxquels je ne pense pas forcément...


Là peu importe, il y a des fonctions qui gèrent ça très bien.
Prends le temps de lire http://fr2.php.net/manual/en/ref.strings.php et en
particulier htmlentities() et htmlspecialchars().

contre, je n'aimerais pas que les utilisateurs voient ces caractères à
l'écran lorsqu'ils reviennent sur leur formulaire (pour modifier)
Le navigateur les interprètera : c'est son boulot. Quand tu lui envoies

&eacute; il affiche bien é.

voudrais pas que dans un champ où ils peuvent entrer, disons, 20
caractères, ils ne puissent en fait en entrer que 12 ou 15.
Toute vérification de la taille des champs côté client est vouée à 'échec

de toutes façons. Mettre un SIZE="10" détermine seulement la taille par
défaut du nombre de caractères affichés après interprétation. Ca n'empêche
pas l'utilisateur de saisir l'Encyclopédia Britannica s'il a du temps à
perdre. Enfin on va dire au moins le premier volume. Ou la lettre A du
Petit Larousse Illustré édition 1929 : les options ne manquent pas.

Plus j'apprends de choses, plus je vois l'étendue de ce qui me reste à
apprendre (:


C'est une fois de plus de ma faute, j'aurais dû commencer par le bonjour
traditionnel sur ce forum et référencé dans la FAQ
(http://faqfclphp.free.fr/)

"Bienvenue chez les fous" :-) ((C)A.F. 1999)

a++
JG


Avatar
Olivier Miakinen

Donc pas mal de caractères là encore : espaces insécables, caractères
accentués, ç et plein d'autres auxquels je ne pense pas forcément...


Là peu importe, il y a des fonctions qui gèrent ça très bien.
Prends le temps de lire http://fr2.php.net/manual/en/ref.strings.php et en
particulier htmlentities() et htmlspecialchars().


Attention quand même aux surprises. Les fonctions htmlentities() et
htmlspecialchars() supposent par défaut que le jeu de caractères est
ISO-8859-1. Heureusement, depuis la version 4.1.0 il est possible de
préciser "ISO-8859-15" comme troisième paramètre.

Voir :
http://fr2.php.net/htmlentities
http://fr2.php.net/htmlspecialchars


Avatar
Pascale
John GALLET écrivait
news::

Là peu importe, il y a des fonctions qui gèrent ça très bien.
Prends le temps de lire http://fr2.php.net/manual/en/ref.strings.php
et en particulier htmlentities() et htmlspecialchars().


J'ai essayé htmlspecialchars() (je n'ai pas forcément besoin de
htmlentities), et cela résout parfaitement mon problème ! Ce qui m'amène à
deux autres questions (1 de résolue, 2 qui se posent...) (-:

- Cela suffit-il à empêcher les utilisateurs d'entrer des scripts vérolés
(je cite l'aide : « htmlspecialchars() est pratique pour éviter que des
données fournies par les utilisateurs contiennent des balises HTML, comme
pour un forum ou un chat. ») ? Ou dois-je quand même contrôler les
caractères entrés comme me l'a expliqué Dr Watson dans un message
précédent ? (oui, je suis une feignasse, je l'admets...)

- De manière tout à fait logique, une fois entré dans la table SQL
correspondante, le contenu du champ « C'est mon très "gros" chien » devient
« C&#039;est mon très &quot;gros&quot; chien » : le problème, c'est que si
mon champ fait 30 caractères, « C'est mon très "gros" chien » passe, mais
la version htmlisée, non. Je peux « limiter les dégâts » en utilisant le
paramètre ENT_NOQUOTES au lieu de ENT_QUOTES puisque les ' ne sont pas un
problème, mais j'en connais qui risquent quand même de couiner parce que le
texte qu'ils ont saisi a été tronqué alors qu'ils avaient bien respecté le
nombre maxi de caractères...

Toute vérification de la taille des champs côté client est vouée à
'échec de toutes façons. Mettre un SIZE="10" détermine seulement la
taille par défaut du nombre de caractères affichés après
interprétation. Ca n'empêche pas l'utilisateur de saisir
l'Encyclopédia Britannica s'il a du temps à perdre. Enfin on va dire
au moins le premier volume. Ou la lettre A du Petit Larousse Illustré
édition 1929 : les options ne manquent pas.


Oui, mais bon, avec un maxlength="10" l'utilisateur ne peut normalement pas
saisir plus de 10 caractères. Si ?

C'est une fois de plus de ma faute, j'aurais dû commencer par le
bonjour traditionnel sur ce forum et référencé dans la FAQ
(http://faqfclphp.free.fr/)


Mais non, c'est pas de ta faute, car l'adresse de la FAQ, je la connais,
elle est même dans mes favoris, mais j'oublie souvent de la consulter alors
qu'elle est très bien faite (:

"Bienvenue chez les fous" :-) ((C)A.F. 1999)


Je m'disais aussi... (o;

--
Pascale

Avatar
John GALLET
Re,

J'ai essayé htmlspecialchars() (je n'ai pas forcément besoin de
htmlentities), et cela résout parfaitement mon problème ! Ce qui m'amène à
deux autres questions (1 de résolue, 2 qui se posent...) (-:

- Cela suffit-il à empêcher les utilisateurs d'entrer des scripts vérolés
Ca dépend où on l'appelle et ça dépend de quel type d'attaque. Petite

galerie des horreurs possibles et quelques remèdes sur
http://www.saphirtech.com/securite.html

- De manière tout à fait logique, une fois entré dans la table SQL
correspondante, le contenu du champ « C'est mon très "gros" chien » devient
« C&#039;est mon très &quot;gros&quot; chien » :


En effet, si on fait la modification avant le stockage, comme je
l'indiquais déjà dans ce thread, il faut prévoir des tailles supérieures.
Cela a aussi d'aures effets de bord, en particulier sur le ORDER BY.

problème, mais j'en connais qui risquent quand même de couiner parce que le
Rôôh, meuuuh non, les utilisateurs ? Couiner pour ça ? Pourquoi

*seulement* pour ça ?

Oui, mais bon, avec un maxlength="10" l'utilisateur ne peut normalement pas
saisir plus de 10 caractères. Si ?
Tout dépend de ce qu'il utilise comme clickodrome. Je t'assure que mon

lynx s'en foutra éperdument, et quand à wget ou curl, je te dis même pas.
Donc il faut voir à quoi/qui sert cette restriction si elle est faite côté
cient. Si c'est pour lui indiquer visuellement qu'au delà de telle taille
il risque de se faire zapper, c'est suffisant.

Bon, reprenons la logique et les contraintes.

On veut saisir un texte dans un clickodrome, le stocker en sgbdr, et le
restituer. Ca devrait pas être si difficile que ça sur le papier. En
pratique, pour pas se faire tarter au passage, c'est moins facile.

Concernant le filtrage des données en entrée, depuis des années, c'était
demerden zie sich elein. Depuis peu, l'extension filter est disponible :
http://fr2.php.net/manual/en/ref.filter.php

A éplucher pour voir si le comportement te convient.

Ensuite, faut-il désamorcer en entrée ou en sortie ? Perso je désamorce en
entrée, quitte à refaire l'opération inverse en sortie si finalement mon
canal n'est pas du html. D'aucuns font l'inverse.
Faut-il désamorcer les xss en convertissant les < et les > ou en utilisant
strip_tags ? Bonne question. La seconde bouffe tout ce qui se trouve entre
< et > sans autre forme de procès, même si ce n'est pas du html :
a<b et b>c => ac

Ca m'empêche pas de l'utiliser, tout dépend du besoin potentiel des
utilisateurs d'entrer ce genre de choses. Dans une application de commerce
électronique, le besoin est totalement nul, pas plus en frontal qu'en
backoffice.

Et enfin les problèmes d'affichage, comme les " perdues dans des
attributs. La seule solution est de les transformer au moment où on les
renvoie vers le navigateur, ou de les avoir transformées avant stockage
dans le sgbd.

a++; JG
--
"L'ennemi, c'est l'utilisateur."

1 2 3