Blog de benji1000

La sécurité des formulaires PHP

Le 28 novembre 2012 dans Développement web

Il est un domaine que l'on ne doit pas oublier lorsque l'on réalise des formulaires en PHP , c'est la sécurité. En effet, les formulaires sont très souvent liés à une adresse mail ou à une base de données ; il est donc judicieux de protéger ces éléments-clé d'un système d'information.

Loin d'être un guide absolu dans le domaine, cet article regroupera quelques bonnes pratiques pour sécuriser un formulaire que j'ai glanées au fil du web.

Choisir la méthode du formulaire

Le premier choix qui s'impose lors de la réalisation d'un formulaire, c'est la méthode de transmission des données d'une page à une autre. Il en existe deux : GET, et POST. Alors que la méthode GET transmet les variables récupérées dans un formulaire par l'URL, la méthode POST les transmet de façon masquée.

Il vous faudra donc choisir, au cas par cas, si les variables récupérées peuvent être affichées au visiteur dans l'URL, ou non. Notez que ce n'est pas parce que les variables sont transmises en POST qu'elles sont totalement invisibles, chiffrées ou sécurisées ; il reste possible de les afficher (ou plutôt, de les intercepter) avec des outils.

Les failles XSS (Cross Site Scripting)

Pour profiter d'une faille XSS, l'attaquant va tenter d'insérer un code (JavaScript, le plus souvent) dans un input d'un formulaire non protégé , ceci afin de modifier le fonctionnement de la page. Prenons le cas d'un forum ; un attaquant pourrait, en exploitant une faille XSS, faire en sorte de subtiliser le cookie de connexion de chaque utilisateur qui se connecterait à ce forum. Ou alors, rediriger tous les utilisateurs vers une page de connexion ressemblant trait pour trait à la charte graphique du forum, mais qui en fait ne servirait qu'à récupérer leurs identifiants de connexion.

Les injections SQL

Pour exécuter une injection SQL, l'attaquant va tenter d'insérer un code dans un input d'un formulaire non protégé qui est relié à une base de données. Ce code peut servir à supprimer tout ou partie de la base de données ! Mais dans le pire des cas, une injection SQL peut permettre d'outrepasser le système d'authentification d'un site, afin d'y entrer sans autorisation (et voir, d'y entrer avec les privilèges de l'administrateur).

Insertion dans une base de données

Pour être sûr que des attaquants n'exécutent pas des injections SQL sur notre base de données, nous devons protéger l'insertion d'une saisie utilisateur grâce aux fonctions :

  • mysql_real_escape_string() : échappe les caractères spéciaux (notamment ' " et NULL) par un antislashs ; étant donné que c'est une fonction de MySQL, vous aurez besoin de vous connecter à votre base avec un mysql_connect() avant de pouvoir l'utiliser
  • addslashes() : réalise la même chose que mysql_real_escape_string(), mais n'est à utiliser que si vous utilisez un type de base de donnée qui ne propose pas ce genre de fonction

Dans le cas où le site que vous développez ne requiert pas que les utilisateurs aient un jour à saisir du code informatique dans leurs messages, on peut utiliser la fonction strip_tags() afin de purement et simplement supprimer les balises de code HTML ou Javascript des messages des utilisateurs.

Affichage depuis une base de données (ou saisie utilisateur)

Trois fonctions s'offrent à nous pour éviter les attaques XSS. Avant de les utiliser, vous devrez vous demander si vous souhaitez que les utilisateurs puissent stocker du code source dans votre base, ou si vous considérez que rien de ce qui n'entre dans votre base n'a besoin d'être du code. Dans le cas d'un forum par exemple, un utilisateur peut légitimement poster un message avec du code sain (utilisez alors l'une des deux premières fonctions).

  • htmlspecialchars() : encode les caractères < > ' " & pour qu'ils soient affichés mais pas exécutés
  • htmlentities() : la même chose que htmlspecialchars(), à la différence qu'elle encode beaucoup plus de caractères ; par exemple, le symbole €, les lettres accentuées é à ù...
  • strip_tags() : supprime carrément toutes les balises contenant < et > qui ne seront pas affichées

Enfin, si vous souhaitez récupérer des données qui ont été insérées en étant protégées par htmlspecialchars(), htmlentities() ou addslashes(), il vous faudra utiliser respectivement htmlspecialchars_decode(), html_entity_decode() et stripslashes().

Exemple concret

Pour finir, voilà un exemple d'un formulaire, avec dessous, la partie "sécurisation" (remarque : ce code sera prochainement obsolète car PHP pousse à l'utilisation de la "PDO" ; voir mon commentaire plus bas pour un exemple d'utilisation) :

<form id="mon_formulaire" method="POST" action="formulaire.php"> <input name=premier_champ type=text placeholder="Premier champ" required> <input name=second_champ type=number placeholder="Second champ" required> <button type=submit name=envoi>Envoi</button> <?php if (isset($_POST['envoi'])) { // Connexion à la base de données mysql_connect($dbhost, $dbuser, $dbpass); mysql_select_db($dbname); // Sécurisation des données reçues $premier_champ = mysql_real_escape_string($premier_champ); $second_champ = mysql_real_escape_string($second_champ); // Création et envoi de la requête $sql = 'INSERT INTO ma_table VALUES("'.$premier_champ.'","'.$second_champ.'")'; mysql_query ($sql) or die ('Erreur SQL !'.$sql.'<br />'.mysql_error()); //Clotûre de la connexion à la base de données. mysql_close (); // Affichage des résultats à l'utilisateur echo 'Vous avez inséré '.htmlspecialchars($premier_champ).'.'; } ?> </form>

Voilà donc quelques méthodes simples pour éviter que votre formulaire soit une passoire :) n'hésitez pas à m'indiquer dans les commentaires si vous avez d'autres astuces pour la sécurisation simple des insertions et lectures de base de données.

XKCD - Exploits of a mom

Pour aller plus loin StackOverflow - How to prevent code injection attacks in PHP (EN) Webmaster Hub - Sécurité et formulaires PHP Apprendre PHP - Traitement des formulaires Chez Neg - Sécurité d'un formulaire PHP [Bastien Rossi - Les injections SQL](Bastien Rossi - Les injections SQL "Bastien Rossi - Les injections SQL") Le blog de maniT4c - Protection de formulaire contre les robots