sécuriser les injections SQL

sigma2008

WRInaute impliqué
Bonjour,
Je créé un formulaire de connexion et d'inscription, tout va bien, maintenant je veux éviter les injections SQL, j'ai lus plein d'article et je souhaite confirmer :)

Dans mon formulaire de connexion j'ai ajouté mysql_real_escape_string() pour éviter l'injection sur SELECT :
Code:
$email=mysql_real_escape_string($_POST['mail']);
$password=mysql_real_escape_string($_POST['password']);
.............
....SELECT * from users where email =$email and password=$password ......

donc là tout est OK select est sécurisée, il reste le formulaire d'inscription, quand je récupère les variables post mail et post password dois je faire la même chose ? C'est à dire mysql_real_escape_string() avant de les insérer ? (insert into ...)

Merci
 

Blount

WRInaute impliqué
Toutes les données provenant du navigateur sont potentiellement un danger.
Donc, à partir du moment où tu vas insérer une donnée en BDD, tu protèges. Que ce soit pour les $_GET et les $_POST mais aussi les $_COOKIES et les données extérieurs.

En règle général, peu importe d'où proviennent les données, s'il s'agit d'une chaîne de caractères, il faut appliquer un mysql_real_escape_string ne serait-ce que pour échapper les caractères ' et ".

Si c'est censé être une valeur numérique, alors tu peux caster la variable: (int) $var ou (float) $var.
 

noren

WRInaute accro
Tout comme frenchhorn, je pense que l'idéal c’est également les requêtes préparées. Pour double sécurité tu peux également faire un contrôle de chaque champ saisi pour voir si ils sont conformes à ce que tu attends.
 

sigma2008

WRInaute impliqué
Merci pour vos réponses, et pour les $_SESSION dois je à chaque fois avant l'insertion dans la bdd ajouter mysql_real_escape_string ? a savoir que les données de sessions sont de provenance bdd et non pas d'un formulaire ou autre.
 

spout

WRInaute accro
Tu peux échapper toutes les données.
Si ça te fait peur, regarde du côté de PDO comme te l'a suggéré frenchhorn.
 

baud74

WRInaute impliqué
sauf erreur, en faisant :
SELECT * from users where email ='$email' and password='$password'
et avec la bonne valeur pour la variable qui va bien, le ' est transformé en \', donc il n'y plus de possibilité de faire une requête sql dangeureuse et valide.
 

Leonick

WRInaute accro
sigma2008 a dit:
pour les $_SESSION dois je à chaque fois avant l'insertion dans la bdd ajouter mysql_real_escape_string ?
tout dépend de ce que tu as laissé mettre dans ton $_SESSION. Si ce sont des données en provenance de l'extérieur et non traitées avant leur affectation, il faut les traiter avant une quelconque utilisation en bdd
 

noren

WRInaute accro
De toute façon mysql_real_escape_string est obsolète

il faut au moins passer par mysqli_real_escape_string

Et comme indiqué le mieux reste malgré tout les requêtes préparées et éventuellement combiné avec un contrôle des champs saisis en amont. Si tu attend par exemple une valeur numérique, un petit test is_numeric() ne fera pas de mal.

Les requêtes préparées peuvent être utilisées avec mysqli si tu ne souhaite pas utiliser pdo :

http://php.net/manual/fr/mysqli.quickstart.prepared-statements.php
 

zeb

WRInaute accro
noren a dit:
Si tu attend par exemple une valeur numérique, un petit test is_numeric() ne fera pas de mal.
Non faut caster et pas réfléchir c'est plus rapide et moins gourmand ... (penser a prévoir le cas par défaut aussi quand on caste)
 

noren

WRInaute accro
Je n'aime pas trop l'idée du caste. En fin de compte tu fais quand même une ou plusieurs actions (update, insert...) alors qu'il y a quoi qu'il en soit un problème dans les données saisies en GET ou POST, par conséquent en faisant de la sorte tu acceptes quand même la requête et peux entrer des valeurs pas forcément bonne ou celles réellement souhaitées à la base par l'internaute.

Alors qu'avec un is_numeric l'action ne peut pas être effectuée, ce qui me semble plus logique si de mauvaises données sont saisies. Et tu avertis l'internaute avec un message.
 

zeb

WRInaute accro
noren a dit:
ce qui me semble plus logique si de mauvaises données sont saisies. Et tu avertis l'internaute avec un message.
Mouais pas convaincu, en info on dépense 10 tonnes d'énergie pour un cas qui risque de se produire toutes les lunes ça c'est un vrai souci (10% du code utilise 90% de la CPU ce qui reviens a dire que 90% du code est quasi jamais utilisé).

Tu n'as qu'a regarder la qualité de l'air de paris pour comprendre que souvent plus simple c'est mieux.

De toute façon sur du numérique, tu as autant de chances que l'utilisateur se plante de valeur, qu'il n'ajoute un caractère alpha, bref tu ne va rien minimiser tu va juste traiter un cas anecdotique (qui n'aurais pas du se produire à ce stade).

Si tu dois vérifier que tu as affaire a un entier ou un float c'est côté client qu'il faut le faire pas côté serveur car quand tu en est arrivé là soit c'est bon soit c'est justement une exploitation de faille donc ton test deviens inutile, car il ne faut pas que de l'alpha passe et c'est tout ; si c'était un utilisateur légitime qui avait fait une connerie tu l'aurais prévenu en amont.

Le code côté serveur il est pas là pour l'utilisateur il est là pour le système, faut distinguer les vérifications normales pour l'utilisation (javascript avec test validité email, fourchette de valeur admissibles, longueur chaines etc ...) et les mesures de protection que tu prend côté serveur pour garantir la validité des données vis a vis de portes que tu n'a pas su voir, à ce stade faut être radical et on en a plu rien a faire de l'utilisateur car si mesure corrective il doit y avoir suite a un oubli de cas possible par l'utilisateur c'est pas dans ce code qu'il faut intervenir mais a la source côté utilisateur.

Bref tu fait comme tu le sent mais perso je vais pas tester si c'est numérique ou pas ça doit être numérique exclusivement donc je caste point barre. D’où ma remarque attention au cas par défaut qu'il faut prévoir. Je te donne un exemple :

Souvent dans les formulaire de login on évoque la faille d'injection qui va permettre de se connecter avec un compte. Ce compte est rarement du au hasard c'est souvent le premier de la liste (premier record de la base donc celui qui va être retourné avec une condition ajouté qui renvoie true) Hors souvent c'est un compte admin vu que c'est le premier a être créé ... Le cas défaut dans ce cas du moins la parade c'est d'injecter systématiquement un compte bidon avec droits ultra limité en premier au cas ou tu ai loupé un truc ...
 

noren

WRInaute accro
Il m'avait toujours semblé qu'il fallait également laisser les tests côté serveurs même si on les effectue déjà côté client (html5, javascript...)

Je comprend tout à fait ton explication, après au niveau du cout CPU, je n'ai jamais vraiment fait de test pour voir l'impact de telles vérifications. Je serais limite tenter de laisser le is_numeric avec en plus un cast avant l'insertion en BDD (en plus des contrôles côté client). :mrgreen: (paranoïa quand tu nous tiens)

Après niveau contrôle côté client à part le javascript (qui peut être désactivé) et le HTML5 qui n'est pas encore bien géré au niveau des formulaires sur tous les navigateurs, je ne vois pas comment effectuer un contrôle client sûr. Le plus fiable m'a toujours semblait être côté serveur malgré tout.

Quoi qu'il en soit merci pour ta remarque, j'en prend note et vais y réfléchir posément, et je vais effectuer quelques tests :wink:
En tout cas c’est pas bête et peut être qu'un cast sera amplement suffisant

PS : je ne connaissais pas cette astuce pour le compte utilisateur. En ce qui me concerne même si quelqu'un arrive a se connecter avec mon compte administrateur il ne pourra rien faire :), il faut ensuite qu'il connaisse l'accès à mon backoffice, sinon il sera comme un utilisateur lambda. J'ose également espérer que les requêtes préparées évitent ce type d'injection.

Mais c’est vraiment chaud d'être "sécure" à 100%. Et dès qu'on manipule des GET/ POST et des espaces membres (sessions...) il faut vraiment être très très prudent.
 

zeb

WRInaute accro
noren a dit:
Il m'avait toujours semblé qu'il fallait également laisser les tests côté serveurs même si on les effectue déjà côté client (html5, javascript...)
Oui tu as raison il faut l'un et l'autre mais tu peux exporter la vérification de format côté client (traiter les cas d'utilisation normal) et te contenter de tests de sécurité côté serveur.

je met souvent pour pas dire toujours de côté le cas javascript désactivé car c'est souvent (chez moi) tout le site qui est impraticable donc par défaut je considère que javascript est là et sinon pas grave l'utilisateur a qu'a être moins ...
Donc a priori un utilisateur normal va se faire interpeler si une data est incorrecte niveau format ... après en base c'est une autre histoire là j'impose le format de façon rigide et si il y a un souci c'est soit un "hacker" soit un bug qui sera remonté et corrigé .... Donc dans tous les cas il ne faut pas aveuglément faire confiance a javascript, mais il est possible d'écarter les use case utilisateur légitimes de la procédure de vérification car c'est censé être fait.

Sinon oui tu as raison gérer des user c'est plus chaud ... mais tellement plus passionnant. Perso j'ai même codé un système de gestion de droits complexe la dedans avec une dizaine de statuts différents et la possibilité d'en ajouter des sur mesure.
 

spout

WRInaute accro
Quand c'est bien pensé, la validation côté client est générée via les contraintes de validation côté serveur (DRY power).
The lib pr validation client: http://parsleyjs.org/

Concernant les failles, on s'en soucie bcp moins quand on utilise un ORM et que les templates sont auto escapés.
 

noren

WRInaute accro
zeb a dit:
noren a dit:
soit un bug qui sera remonté et corrigé ....

En parlant de bug remontée et corrigé, j'ai ouvert un topic qui a fait un flop :

https://www.webrankinfo.com/forum/t/gestion-des-erreurs-mysql-en-production.177223/

J'en profite donc pour te poser la question. :oops:

je ne sais pas si tu utilises PDO, mais comment gère tu les erreurs sql en production, laisse tu le mode PDO::ERRMODE_EXCEPTION activé

ou le met tu en mode SILENT?

le soucis en le mettant en mode silent, c’est comment être informé des erreurs SQL rencontrées en prod? et si on utilise les transactions comment intercepter une erreur pour faire un rollback? Puisque dans ce cas le try catch (exception ou pdoexception) ne sert plus à rien
 

noren

WRInaute accro
@spout : Sans forcément parler ORM, les requetes préparées se suffisent ou non?

Avec une requête du type (c’est une exemple hein) :

Code:
select id, login from user where id = ? and pass = ?

puis un

Code:
execute(array($id, $pass));

Dans ce cas on évite les problèmes d'injection non?, et normalement il y a dans cette requête automatiquement un contrôle et une gestion du typage non?

Si l'id n'est pas numerique pas de risque d'intrusion? Et la requête ne peut pas donner suite. A moins qu'elle fasse également automatiquement un cast (faudrait que je fasse l'essai)

et si a la place de id = ? , je mettais login = ? idem aucun risque d'injection? les " '--" etc. n'auraient aucun impact?

Je dois avouer que pour le moment je me suis contenter d'un contrôle sur les champs saisis (dans la mesure du possible), de requêtes préparées et de htmlspecialchars a l'affichage.
Et pour le vol de session j'utilise :
session_regenerate_id(true);
J'oublie certainement encore plein de failles de sécurité. Après j'ai l'avantage de ne pas utiliser un CMS ou framework connu qui sont certainement étudiés à la loupe par les hacker.
 

zeb

WRInaute accro
noren a dit:
je ne sais pas si tu utilises PDO, mais comment gère tu les erreurs sql en production, laisse tu le mode PDO::ERRMODE_EXCEPTION activé
Non j'utilise pas, le passage msqli est prévu pour cette année après une refonte de design en cours. En tous cas j'ai un opérateur de silence sur toutes les fonctions SQL. J'ai trop chassé les erreurs SQL sur google pour laisser passer les miennes :D
 

noren

WRInaute accro
ok, bon bin je vais voir si je ne vais pas mettre en SILENT en général et en exception uniquement lorsque je traite des transactions.

l'avantage de laisser en mode exception : si un petit malin arrive fait planter une requete en faisant des tentative d'injections je pouvais créer un log et voir la requête tentée. En SILENT, pour avoir un retour des requêtes qui ont planté et sur mutualisé c’est plus embêtant.
 

Discussions similaires

Haut