Questions sécurités et pratiques

Répondre


Cette question est un moyen d’empêcher des soumissions automatisées de formulaires par des robots.
Smileys
:D :) :( :o :shock: :? 8-) :lol: :x :P :oops: :cry: :evil: :twisted: :roll: :wink: :!: :?: :idea: :arrow: :| :mrgreen: =D> #-o =P~ :^o :non: :priere: 8-|
Voir plus de smileys
  Revue du sujet
 

  Étendre la vue Revue du sujet : Questions sécurités et pratiques

par AB » 27 juin 2007, 23:07

Par exemple si dans un forum tu supprimes la possibilité d'enregistrer certains caractères, comment vont faire les personnes qui auraient besoin de les utiliser pour par exemple écrire <ceci>:
"La déclaration d'un code php commence par <?php et se termine par ?>. Dans le code HTML, pour indiquer un lien simple on utilise le plus souvent la syntaxe suivante <a href="lien" >texte du lien </a>"

Donc si tu ne veux pas limiter les messages (qui auraient besoin d'utiliser ces caractères) dans un forum, le mieux est d'enregistrer les tags dans la bdd puis de les protéger par exemple par un htmlentities() lors de l'affichage pour qu'ils ne soient pas interprétés mais néanmoins affichés :wink:

par Snipy » 26 juin 2007, 21:31

cependant, pour le strip_tags(), si tu n'acceptes pas les tags, pourquoi les stocker? autant les supprimer tout de suite, non?
Dans l'absolu évidemment, mais dans la pratique on change parfois d'avis et dans ce cas si tu n'as pas choisi la soluce la plus souple tu vas galérer :wink:
Tu penses à quoi par exemple ?


naholyr > Grand dieu toute mes escuses
:P

par Shrell » 26 juin 2007, 19:25

:twisted: :twisted: :twisted: oui mais moi suis un tortionnaire, mes utilisateurs doivent déjà s'estimer heureux de pouvoir rentrer du texte quelque part, alors il vont pas se plaindre si je leur interdis le HTML :twisted: :twisted: :twisted:

par AB » 26 juin 2007, 17:59

cependant, pour le strip_tags(), si tu n'acceptes pas les tags, pourquoi les stocker? autant les supprimer tout de suite, non?
Dans l'absolu évidemment, mais dans la pratique on change parfois d'avis et dans ce cas si tu n'as pas choisi la soluce la plus souple tu vas galérer :wink:

par Shrell » 26 juin 2007, 17:42

:priere: je te prie Ô grand naholyr de m'excuser de mon impertinence :priere:
(hé bé la qualité des modos ici, c'est plus ce que c'était :twisted: :-# )

par naholyr » 26 juin 2007, 17:31

Je vous interdis de me dire que je suis hors-sujet ! Je suis admin :evil:
Ouais bon, ok, j'avais lu en diagonale comme d'habitude :( (toujours est-il que le placeholder est un principe intéressant à mettre en pratique)

par Shrell » 26 juin 2007, 17:22

Heu, strip_tags et autre htmlspecialchars ne vous protègeront PAS DU TOUT contre les SQL-injections.
Normalement, la bonne pratique veut que l'on stocke en base le texte tel qu'il a été entré, les manips dont vous parlez doivent se faire juste avant l'affichage, pas au moment du stockage.

Au stockage la seule chose à laquelle on doit faire attention, c'est :
- la cohérence des données
- la prévention des injections sql
Je suis tout à fait d'accord avec toi, et d'ailleurs on ne parlait pas là de protection contre les injections ;)
Je suis aussi d'accord sur le fait qu'il faille enregistrer les données brutes, et donc ne pas utiliser htmlspecialchars() au moment de l'insert
cependant, pour le strip_tags(), si tu n'acceptes pas les tags, pourquoi les stocker? autant les supprimer tout de suite, non?

par Snipy » 26 juin 2007, 16:25

Heu, strip_tags et autre htmlspecialchars ne vous protègeront PAS DU TOUT contre les SQL-injections.
Normalement, la bonne pratique veut que l'on stocke en base le texte tel qu'il a été entré, les manips dont vous parlez doivent se faire juste avant l'affichage, pas au moment du stockage.

Au stockage la seule chose à laquelle on doit faire attention, c'est :
- la cohérence des données
- la prévention des injections sql
Tu as probablement mal lu mes posts,
Je parle bien entendu de prévention d'injection sql avant l'entrée dans la BDD par la fonction mysql_real_escape_string()

Mais ma question suivante était de savoir ce qu'il fallait mieux faire entre strip_tags et autre htmlspecialchars à la sortie des informations de la BDD dans le cadre de leur affichage

par naholyr » 26 juin 2007, 16:22

Heu, strip_tags et autre htmlspecialchars ne vous protègeront PAS DU TOUT contre les SQL-injections.
Normalement, la bonne pratique veut que l'on stocke en base le texte tel qu'il a été entré, les manips dont vous parlez doivent se faire juste avant l'affichage, pas au moment du stockage.

Au stockage la seule chose à laquelle on doit faire attention, c'est :
- la cohérence des données
- la prévention des injections sql

par Snipy » 26 juin 2007, 15:56

Strip_tag à l'ai le plus interessant, mais il n'y a pas de risque que certaines donnees passe çà la trappe (cf les avertissement données dans la doc)
Par habitude vous utilisez quoi ?

Sinon naholyr je garde ton idée de coté, le jour ou je me sentirias pret :P

par naholyr » 26 juin 2007, 15:50

Le plus simple c'est de se créer des "placeholders", typiquement c'est fait avec des points d'interrogations:
$requete = construitRequete('SELECT * FROM maTable WHERE champ = ?', $maVariable);
On n'a pas besoin de s'occuper au moment de la construction de la requête de l'utilisation de mysql_real_escape_string(), etc... C'est typiquement le genre de chose qu'on retrouve dans des couches d'abstraction de bases de données, car les fonctions d'échappements dépendant de la base de données, elles doivent être abstraites également :)

Pour se faire un constructeur de requêtes maison, c'est assez simple avec sprintf et %s (l'utilisation du point d'interogation pose quelques soucis qu'on aura ici la flemme de résoudre, avec sprintf c'est facile et on a l'habitude, pour afficher un '%' il faut mettre '%%', classique) :
function construitRequete($requete) {
	$args = func_get_args();
	array_shift($args);
	foreach ($args as &$arg) {
		switch (gettype($arg)) {
			case 'string':
				$arg = '"' . mysql_real_escape_string($arg) . '"';
				break;
			case 'bool':
			case 'boolean':
				$arg = $arg ? 1 : 0;
				break;
			case 'array':
				foreach ($arg as &$element) {
					$element = construitRequete('%s', $element);
				}
				$arg = implode(',',$arg);
				break;
		}
	}
	array_unshift($args, $requete);
	return call_user_func_array('sprintf', $args);
}
C'est un bon exercice de faire ça une fois dans sa vie, ne serait-ce que pour l'apprivoisement de call_user_func_array(), func_get_args() et autres fonctions qu'on utilise rarement.

Résultat :
$nom = 'Toto"; # DELETE FROM maTable'; // Tentative de hack
$id = 3; // un entier
$classes = array('6eA','6eB','6eC'); // un tableau
echo construitRequete('SELECT * FROM elves WHERE id=%s OR nom=%s OR classe IN (%s)', $id, $nom, $classes);
donne

Code : Tout sélectionner

SELECT * FROM elves WHERE id=3 OR nom="Toto\"; # DELETE FROM maTable" OR classe IN ("6eA","6eB","6eC")
Et ça devient tout de suite beaucoup plus simple de construire des requêtes sécurisées, sans avoir bourrer son code d'appels à mysql_real_escape_string() ;)

Moralité : Utilisez une couche d'abstration d'accès à la base de données, vous aurez forcément un support des "placeholders". Et si ce n'est pas le cas n'hésitez pas à construire le votre.

par Shrell » 26 juin 2007, 15:41

Tout dépend si tu veux ou non que l'utilisateur PUISSE le faire
si il peut
-> tu ne fais rien, sinon elles ne s'afficheront pas (enfin si, au contraire, elle s'afficheront en tant que TEXTE en plein milieu du contenu, ce n'est pas du meilleur effet :? )
si il ne peut pas
-> soit tu fais un htmlspecialchars(), et là, comme dit plus haut, elles s'afficheront mais n'auront aucun effet
-> soit tu fais un strip_tags(), ce qui supprimera purement et simplement tout ce qui ressemble à du HTML

Pour les champs qui n'ont que deux valeurs (ou plus, mais qui ne peuvent en prendre qu'une seule à la fois), mysql propose un type fait exprès : ENUM
ca revient au même que ce que tu fais actuellement (d'ailleurs je crois me souvenir que c'est de cette façon qu'il est stocké), mais ca a le mérite d'être beaucoup plus lisible : 'OUI' ou 'NON' est plus compréhensible que 0 ou 1

par AB » 26 juin 2007, 15:36

Si tu lis la doc : mysql_escape_string est dépréciée, utilisez à la place mysql_real_escape_string()
donc t'as pas de question à te poser sur ce sujet. Si ton serveur utilise une version php > 4.3 tu utilises
mysql_real_escape_string() et c'est suffisant pour protéger tes requêtes.

Bon je vois que je me suis fais grillé.

htmlspecialchars() ou htmlentities n'est utile que pour protéger l'affichage de tes données

par Snipy » 26 juin 2007, 15:35

Merci pour vos 2 réponses,
Pour revenir au premier point, si l'utilisateurs transmet des balises html, mysql_real_escape_string() n'y fera rien, donc à la sortie est on contraint à un htmlspecialchars() ?



Et nouvelle question, pour les champs qui peuvent avoir que 2 valeurs, quel est la meilleur façon de procéder actuellement je remplis soit par 1 (pour vrai en gros) soit par 0.

Merci :)

par Shrell » 26 juin 2007, 15:30

1/ En théorie les données stockées en base de données doivent etre brutes, afin de pouvoir les utiliser par la suite n'importe où, donc à priori je dirais NON au htmlspecialchars() lors des insert

La différence entre mysql_escape_string() et mysql_real_escape_string() est expliquée clairement dans le manuel : la seconde t'oblige à avoir une connection mysql active au moment où tu l'utilises (d'ailleurs elle tombe en erreur si il n'y en a pas) ET utilise le jeu de caractère courant (UTF-8, etc...), alors que la seconde ne se préoccupe pas de ce genre de "détail" et peut donc faire des choses bizarroïdes pour peu que tu sortes du traditionnel ISO-8859-1, qui est le jeu de caractères par défaut de PHP

2/ Personnellement, étant donné que j'utilise des guillemets simples pour entourer mes champs, j'utilise des doubles pour entourer ma requête, ce qui m'évite les échappements de guillemets à n'en plus finir... déjà que je n'ai aucun mal à oublier de fermer mes guillemets, si en plus je dois les échapper ! :shock:
Certains te diront surement que l'usage de guillemets simples accélerera le script, étant donné que les chaines entre guillemets simples ne sont pas interprétées, je dirais que c'est gagner des queues de cerises... Enfin après, question d'habitude ;)

La différence entre les deux requêtes que tu proposes c'est que dans le premier cas, comme tu l'as souligné, tu transmets une chaine de caractères : il faut donc la limiter, c'est le role des guillemets (sinon, comment distinguer une chaine de caractères au beau milieu d'une requete, qui elle meme est une chaine de caractères ?).
Dans le second cas, c'est un nombre, qui n'a donc aucun besoin de limiteurs. Donc => pas de guillemet.

Si certains points ne sont toujours pas clairs n'hésite pas ;)