Vous êtes sur la page 1sur 3

Sécurité

Les problèmes
de sécurité avec PHP
Si votre site web utilise PHP et éventuellement une base de données
MySQL alors vous devez connaître les principales failles de sécurité de
PHP comme l'injection SQL, les failles XSS, les failles d'include, les failles de
sessions et les failles d'upload.

régulières couplées à la fonctions preg_match


Cet article explique... Ce qu'il faut savoir... pour vérifier que le nom du fichier ne con-
• Quelles sont les principales failles de sécurité • Vous devez avoir des bases en programmation tient pas de caractères spéciaux, de backslash
en PHP. PHP et SQL. et de slash. Le Listing 1 vous montre comment
• Comment se protéger contre ses failles. sécuriser votre code.
Deuxième problème avec l'upload de fichiers
en php, la taille du fichier. Même si une taille
maximale est spécifiée dans le php.ini pour évi-
verses informations sur le fichier que vous sou- ter tout problème sur le serveur, il est préférable
haitez uploader : de vérifier si la taille du fichier est acceptable
Niveau de difficulté pour notre script. Pour cela, on utilise la varia-
• Le nom : $ _ FILES['avatar']['name'], ble $_FILES['fichier']['tmp_name'] que l'on
• Le chemin du fichier temporaire : passe en paramètre à la fonction filesize()
$ _ FILES['avatar']['tmp _ name'], pour récupérer la taille du fichier que le visi-

L
orsque vous codez un site web en PHP • La taille (peu fiable, dépend du navigateur) : teur souhaite uploader. On déclare ensuite une
ou autre, vous devez être conscient des $ _ FILES['avatar']['size'], variable contenant la taille maximale acceptée
failles de sécurité qui existent. Une • Le type MIME (peu fiable, dépend du na- (en octets) et on la compare à filesize($_
faille de sécurité est une vulnérabilité dans vo- vigateur) : $ _ FILES['avatar']['type'], FILES['fichier']['tmp_name']). Si la variable
tre code qui permet à un pirate informatique • Un code d'erreur si besoin : $ _ FILES[ est inférieure au résultat de la fonction alors on
d'exécuter des commandes qu'il n'est pas censé 'avatar']['error']. peut continuer le script (Listing 2).
pouvoir effectuer. Par exemple, un pirate peut Une fois ces deux tests effectués, vous pouvez
via une faille de sécurité sur votre site s'identi- Ces variables nous seront très utiles pour effec- utiliser la fonction move_uploaded_file pour
fier sur votre site web et récupérer des informa- tuer nos tests. déplacer le fichier du visiteur dans le répertoire
tions personnelles sur vos utilisateurs, détruire Maintenant que le sujet est introduit, nous spécifié en paramètre.
votre site web ou encore utiliser l'espace disque allons voir les problèmes que posent les for-
de votre site web comme espace de stockage mulaires d'upload. Par exemple, si vous ne Les failles d'include ?
pour des fichiers illégaux. C'est pour toutes ces contrôlez pas l'extension du fichier uploadé, Lorsque l'on fait un site en PHP, il est très pratique
raisons que nous allons apprendre à nous pro- le visiteur peut très bien envoyer un fichier d'utiliser des include. Ce qui donne des URL du
téger contre ces failles de sécurité en PHP. Cet .php ou autre permettant de récupérer des type : http://www.monsite.fr?p=page
article sera divisé en cinq parties correspondant informations sensibles sur votre serveur. Pour Si vous ne sécurisez pas vos include, un utilisa-
aux cinq types de faille que nous allons décou- cela, nous allons appliquer une simple con- teur mal intentionné pourra facilement exécuter
vrir : les failles d'upload, les failles d'include, dition couplée à la fonction strrchr (cette du code à votre insu sur votre page. Depuis PHP 5
l'injection SQL en PHP, les failles XSS (CSS) et fonction permet de récupérer l'extension d'un ce problème est résolu puisqu'il n'est plus possible
les failles de sessions. fichier, comme par exemple .gif) permettant par défaut d'appeler une page externe au serveur
de vérifier si le fichier uploadé a bien l'exten- dans un include. Cependant pour les serveurs
Les failles d'upload ? sion .jpeg, .jpg, .gif ou .png ou autre que vous sous PHP 4 ce problème persiste par défaut. Pre-
Pour votre site web il peut être utile de créer un aurez spécifié dans un tableau. Vous devez nons l'exemple du Listing 3.
formulaire permettant à vos visiteurs d'uploa- également vérifier que le nom du fichier ne Si par exemple notre page est disponible
der par exemple des images pour leurs avatars. contienne pas de caractères spéciaux. Un visi- à l'adresse suivante : http://www.monsite.fr/
Cependant l'upload de fichiers par des visi- teur mal intentionné ayant uploadé une image index.php?p=http://www.google.fr alors la page affi-
teurs est risqué si on ne respecte pas quelques avec un nom du type essai.php/0.png, pourrait chera la page de Google. Imaginez donc, un utili-
règles. via les fonctions fopen, fwrite et fclose exé- sateur mal intentionné peut envoyer à votre page
Une fois votre <form></form> en place avec cuter exécuter du code php au travers de l'ima- une URL renvoyant vers un fichier contenant du
une method="POST", vous pouvez récupérer di- ge. Pour cela, on va utiliser les expressions code permettant d'exécuter du code sur votre

64 04/2008
Les problèmes de sécurité avec PHP

serveur. Pour éviter cela utilisez encore les con- L'injection SQL en PHP ? plus clair : admettons que dans votre base de don-
ditions. Dans le Listing 4 nous reprenons le code L'injection SQL est peut être l'un des problèmes nées vous avez une table avec quatre champs : id,
du Listing 2 mais en le sécurisant. L'utilisateur les plus connus en PHP, comme vous allez le voir, login, mot_de_passe, compte_bancaire et que
malveillant ne peut désormais plus inclure n'im- elle fait partie des failles XSS. Elle permet notam- sur votre page web, vous avez un petit formulaire
porte quelle page dans votre page. Seules les pages ment de se connecter en tant qu'administrateur avec deux input (login et mot_de_passe) pour
explicitement spécifiées dans votre page pourront en court-circuitant la vérification des données en- qu'un utilisateur puisse en entrant le bon couple
être incluses. trées. Vous pouvez aussi récupérer des informa- login/mot_de_passe récupérer son numéro de
Pour un peu plus de sécurité, vous pouvez éga- tions situées dans la base de données auxquelles compte bancaire. Une fois le formulaire envoyé,
lement utiliser la fonction require() au lieu de la vous ne devriez pas avoir accès. Un exemple sera vous allez simplement récupérer le numéro de
fonction include(). Le principe est exactement
le même, mis à part que require() provoque une Listing 1. Vérifier l'extension et le nom du fichier uploadé
erreur fatale en cas de problème alors que include
provoque simplement des Warnings. <?php
$extensions = array('.jpeg', '.png', '.gif');
Les failles XSS (CSS) ? $fichier = $_FILES['fichier']['name'];
Les failles XSS (Cross Site Scripting), à ne pas con- if(preg_match('#[\x00-\x1F\x7F-\x9F/\\\\]#', $fichier))
fondre avec le CSS (Cascading Style Sheet). Les // vérifie qu'il n'y a pas de caractères spéciaux
failles XSS permettent l'injection SQL (que nous echo 'Le nom du fichier comporte des caratères interdits, merci de ne pas
aborderons juste après) mais permet aussi d'injec- utiliser des / et autres caractères spéciaux';
ter du code dans un site web. Sur un site mal pro- $extension = strrchr($fichier, '.');
tégé, un formulaire demandera une information if (!in_array($extension, $extensions))
au visiteur (login, etc...), si ensuite la variable passe echo 'Le format de fichier n\'est pas accepté. Seuls le jpeg, le png et le gif
en GET (visible dans l'URL) alors l'utilisateur mal- sont acceptés';
veillant pourra exécuter du javascript. Exemple : ?>

http://www.monsite.com/index.php?p= Listing 2. Vérifier la taille du fichier uploadé


<script>alert("Faille XSS");</script>
<?php
Ici on aura une petite boite de dialogue avec ins- $taille_max = 10000;
crit "Faille XSS", le code peut être beaucoup $taille_fichier = filesize($_FILES['fichier']['tmp_name']);
plus malicieux. Pour nous protéger, il faudra uti- if ($taille_fichier > $taille_max)
liser des fonctions pour protéger le contenu des echo 'Le fichier est trop gros, upload impossible, la taille maximale est de
données que l'utilisateur transmettra. Il existe 10Mo';
plusieurs fonctions effectuant plus ou moins la ?>
même tâche. Pour ma part, je préconise :
Listing 3. Include non sécurisé
htmlentities($_GET['donnee'], ENT_QUOTES);
<?php
Cette fonction permet de convertir les caractères if(isset($_GET['p']) {
dangereux (>, ', ", ...). $page = $_GET['p'];
Grâce à cette fonction les simples quote ', se- include($page);
ront transformées en HTML, c'est à dire &quot;. } else
Il faut également savoir qu'il est pour ainsi dire echo 'pas de page a inclure';
impossible de se protéger à 100% contre les failles ?>
XSS. En effet les failles XSS dépendent du naviga-
teur du client, ce qui ne peut pas être gérer par le Listing 4. Include sécurisé
serveur qui fait tourner votre site web. Prenons
l'exemple d'un site disposant d'un formulaire per- <?php
mettant l'envoi d'images qui seront ensuite utili- if(isset($_GET['p']) and $_GET['p'] == 'page.php') {
sées comme avatars. Ce type de formulaire est très $page = $_GET['p'];
dangereux pour la majeure partie des anciens navi- include($page);
gateurs comme Netscape 8.1, Internet Explorer 6 } else
etc. car il est possible d'exécuter du javascript dans echo 'pas de page à inclure ou page non autorisée';
l'attribut src de la balise img. Chaque fois qu'un vi- ?>
siteur chargera votre image, il exécutera votre code
javascript. Fort heureusement, les dernières ver- Listing 5. Requête SQL sécurisée
sions des navigateurs (Firefox 2, Internet Explorer
7 par exemple) sont de mieux en mieux protégés <?php
contre ce type de problème. Comme dit ci-dessus, $login = htmlentities($_POST['login'], ENT_QUOTES);
ces failles dépendent du navigateur utilisé, ce type $mot_de_passe = md5(mysql_real_escape_string($_POST['mot_de_passe']));
d'attaque est donc très aléatoire et par conséquent mysql_query('SELECT compte_bancaire FROM table WHERE login=' . $login
très dangereux. Le pirate peut donc varier ses tech- .' AND mot_de_passe=' . $mot_de_passe . ';');
niques et ainsi piéger le visiteur sans que le serveur ?>
hébergeant le site web ne puisse intervenir.

www.phpsolmag.org 65
Sécurité

compte avec une requête SQL SELECT. Votre co- 1 est toujours égal à 1. Autre façon d'accéder aux cédent corrigé (Listing 5). Dans cet article, nous
de PHP ressemblera donc à : données, en utilisant le caractère # qui en SQL n'avons vu que l'injection SQL sur une requête
marque le début d'un commentaire, le code situé SELECT mais il existe d'autres types d'injection,
mysql_query('SELECT compte_bancaire FROM à droite du # n'est donc pas exécuté ce qui per- pour les connaître, je vous renvoie vers l'article de
table WHERE login=' . $_POST['login'] met ici de ne rentrer que le nom de l'utilisateur David Michaud paru dans le numéro 6/2007.
.' AND mot_de_passe=' . md5($_ suivi d'un # ce qui permet de récupérer le numé-
POST['mot_de_passe]) . ';'); ro de compte bancaire de l'utilisateur spécifié. Les cookies ?
Pour nous protéger de ce problème, il va falloir Les cookies sont des petits fichiers enregistrés sur
Si vous faites cela, des utilisateurs peu scrupu- sécuriser les données que l'utilisateur transmet. le disque dur du visiteur. Ils enregistrent les habi-
leux pourront récupérer tous les numéros de Pour cela, il faut utiliser la fonction mysql_real_ tudes du visiteurs, les pages qu'ils visitent etc... Le
comptes ou un numéro de compte appartenant escape_string() qui permet de convertir les webmaster peut ainsi se servir de ses cookies pour
à quelqu'un en particulier. Ce problème vient données de l'utilisateur, la simple quote sera ainsi adapter son site en fonction des informations re-
du fait que vous faites confiance aux données transformée en \' ce qui évitera les problèmes cueillies dans le cookie. Les cookies ont une du-
que l'utilisateur transmet à votre serveur, ce qui évoqués ci-dessus. Il est préférable d'utiliser cette rée de vie limitée qui est définie par le concepteur
est une grosse erreur. Par exemple si l'utilisateur fonction plutôt que addslashes ou htmlentities du site. Pour un grand nombre de personnes, les
rentre comme login : ' or '1' = '1' et la même cho- car si l'on utilise un langage qui n'est pas dédié cookies riment souvent avec surveillance et vie
se comme mot de passe alors le script retourne- au web (exemple Java), l'affichage risque de po- privée.
ra tous les champs compte _ bancaire puisque ser quelques problèmes. Voici donc le code pré- Les cookies sont donc très utiles pour les sites
web par exemple pour stocker le template préféré
du visiteur ou tout autre information évitant ainsi
Sur Internet de redemander à chaque visite les mêmes choses
• http://www.nexen.net – Site regroupant toutes les fonctions disponibles en PHP, (template...). Il peut être tentant de stocker par
• http://www.phpsecure.info – Site dédié à la sécurité. exemple le mot de passe de l'utilisateur (crypté ou
non) dans un cookie pour qu'il n'est plus à rentrer
son mot de passe à chaque visite. Ne le faites pas !
Listing 6. Code non sécurisé utiisant les cookies Il est très facile grâce au javascript notamment
de récupérer des cookies et ainsi avoir accès aux
<?php données du visiteur. Le Listing 6 est un exemple
$mot_de_passe_admin = md5('mdp'); // le bon mot de passe admin de code à ne pas mettre sur votre site web (vous
$mot_de_passe = $_COOKIE['mot_de_passe']; noterez que dans cet exemple pour une meilleur
// le mot de passe hashé en md5 contenu dans le cookie compréhension du code j'ai stocké le bon mot de
if ($mot_de_passe == $mot_de_passe_admin) // on compare les 2 mots de passe passe administrateur directement en dur dans le
echo 'Vous êtes admin'; code, c'est à éviter, il préférable d'utiliser une base
else de données MySQL par exemple).
die('Vous n\'êtes pas admin'); Pour réaliser un équivalent plus sécurisé, utili-
?> sez les sessions. Nous allons voir dans le Listing 7
et le Listing 8 le code équivalent au Listing 6 mais
Listing 7. Enregistrer une session en utilisant des sessions (notez que le mot de pas-
se administrateur est toujours en dur pour une
<?php meilleure compréhension).
// code à mettre sur la page de login
session_start(); // on démarre la session Conclusion
$mot_de_passe_admin = md5('mdp'); // le bon mot de passe admin Après la lecture de cet article vous devriez être en
$mot_de_passe = md5($_POST['mot_de_passe']); mesure de mettre en place une stratégie de base
// le mot de passe hashé en md5 récupéré dans le formulaire d'authentification pour votre site web codé en PHP. Bien sûr, avec
if ( isset($mot_de_passe) and $mot_de_passe == $mot_de_passe_admin) cet article, votre site ne sera pas sécurisé à 100%,
// on vérifie que la variable $mot_de_passe existe et on compare les 2 mots de passe d'ailleurs un site sécurisé à 100% n'existe pas.
session_register('mot_de_passe') // on enregistre la session avec le mot de passe Le but de cet article étant de vous faire prendre
else conscience des moyens très simples de sécuriser
die('Mauvais mot de passe'); son site. N'oubliez pas qu'une des grandes devises
?> d'internet et de la programmation en générale est
de ne jamais faire confiance à des données exter-
Listing 8. Sécuriser une page privée nes. Dans notre cas, ne jamais faire confiance aux
données ou fichiers transmis par le visiteur, il faut
<?php donc au maximum vérifier les entrées de l'utilisa-
// code à mettre sur les pages réservées à l'administrateur teur pour éviter tout problème.
if(session_is_registered('mot_de_passe'))
// on vérifie que la session mot de passe est enregistrée
echo 'Vous pouvez accéder à la page'; AYMERIC LAGIER
// si elle est enregistrée, on affiche la partie administrateur Aymeric Lagier est étudiant à l'ESI – École Supérieu-
else re d'Informatique – SUPINFO. Il programme en PHP
die('dehors !'); // sinon on arrête l'exécution de la page depuis plus de quatre ans.
?> Site web : http://www.aymericlagier.fr
Conract : aymeric.lagier@supinfo.com

66 04/2008