Sécuriser son code PHP

Décembre 2016


Indépendamment de la sécurisation du système d'exploitation du serveur, du serveur HTTP lui-même et des options de configuration de PHP (php.ini), il est important de veiller à sécuriser les données provenant des utilisateurs (via les formulaires ou les URL par exemple), car c'est généralement de là que proviennent la majeure partie des attaques web.

Ces contrôles préventifs peuvent globalement se classer en trois grandes catégories :


Valider les saisies des utilisateurs


Lorsque le site présente des formulaires permettant aux utilisateurs de saisir et d’envoyer du contenu, il ne suffit pas de leur indiquer le format des données à saisir (adresse électronique, numéro de téléphone, quantité de produits), il faut également contrôler côté serveur (par exemple en PHP) si les données sont conformes à ce que l’on attendait. Mieux. Lorsqu’il s’agit de nombres entiers, il suffit par exemple de convertir les données envoyées par l’utilisateur en entier :
<?php $nombre_d_articles = intval($_REQUEST['nombre_d_articles']); ?>

Valider les données transmises par url ou par formulaire


Dans beaucoup de cas, les données transmises d’une page à l’autre le sont via l’URL (méthode GET) ou grâce à un formulaire (méthode GET ou (méthode POST) que le webmaster a mis en place. Il n’est ainsi pas rare qu’une URL se termine par un paramètre désignant la rubrique à afficher, comme dans l’exemple suivant :
/index.php?rub=25

Les utilisateurs ne sont pas sensés avoir à modifier ce paramètre à la main, mais il faut toujours garder à l’esprit que cela est possible. Que se passerait-il si un utilisateur modifiait l’URL d’une des façons suivantes :
/index.php?rub=0
/index.php?rub=
/index.php?rub=aaaaAAAAAaaaa
/index.php?rub=1+or+1

Quel que soit le type de données transmises par URL ou par formulaire, il est indispensable de vérifier que son format est bien celui attendu !

Pour cela vous pouvez par exemple utiliser la fonction filter_input().
Prenons un exemple avec cette fonction. Un utilisateur vous a envoyé une adresse email par un formulaire de type post. Le champs s'appelait "email". Pour le récupérer il vous faut procéder comme ça:
$email = filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL);
if($email){
    //L'adresse email entrée possède bien un format d'adresse mail
}

Vous pouvez filtrer de nombreuses choses en utilisant cette fonction: les adresses IP, les url. Vous pouvez également appliquer des modifications comme par exemple encoder une chaine prévue pour être passée dans une url, comme l'aurait fait htmlentities(). Plusieurs filtres peuvent être combinés en utilisant l'opérateur bit à bit "|".
Exemple pour ne valider une ip passée dans une url que si elle correspond au format d'une Ipv4:
$ip = filter_input(INPUT_GET, 'ip', FILTER_VALIDATE_IP | FILTER_FLAG_IPV4);

Vous trouverez tous les filtres utilisables à cette adresse.

NOTE: Si vous avez besoin d'appliquer un filtre directement à une variable, vous pouvez utiliser filter_var().

Échapper le contenu affiché ou transmis par url


Lorsque le contenu saisi par l’utilisateur est affiché à l’écran, il se peut que celui-ci contienne du code HTML ou du code JavaScript, c’est la raison pour laquelle il faut protéger – le terme approprié est échapper – le contenu de l’utilisateur :
Si le contenu est destiné à être affiché en HTML : il faut HTMLencoder le contenu avant de l’afficher, c’est-à-dire transformer tous les caractères spéciaux en leurs entités HTML équivalentes. PHP possède une fonction permettant d’automatiser ce processus :
echo htmlentities($_REQUEST['contenu']);


Si le contenu est destiné à être affiché dans une URL : il faut URLencoder le contenu avant de le passer en paramètre d’une URL. PHP possède deux fonctions permettant de faire cet encodage : urlencode() et rawurlencode(). La différence entre ces deux fonctions tient à l’encodage d’un espace, qui dans le premier cas donne %20 et donne « + » dans le second.
echo 'http://www.monsite?valeur='.urlencode($_REQUEST['valeur']);


Si le contenu est destiné à être enregistré dans une base de données : il est nécessaire d’échapper tous les caractères ayant une fonction spécifique dans le serveur de base de données utilisé. Dans le cas de PHP et MySQL, la fonction mysql_escape_string() transforme tous les caractères potentiellement nuisibles contenus dans la chaîne de caractères passée en paramètre.
$query = 'SELECT id FROM matable WHERE user=&#8221;'.mysql_escape_string($_REQUEST['user']).'&#8221;';


Notez que si le serveur PHP est configuré avec l'option magic_quotes, les données transmises par les utilisateurs sont automatiquement protégées avec des barres obliques inverses (antislashes). Ainsi, avant de les protéger avec mysql_escape_string, il faut "défaire" cette protection de base :
$query = 'SELECT id FROM matable WHERE user=&#8221;'.stripslashes(mysql_escape_string($_REQUEST['user'])).'&#8221;';

A voir aussi


A voir également :

Ce document intitulé «  Sécuriser son code PHP  » issu de CommentCaMarche (www.commentcamarche.net) est mis à disposition sous les termes de la licence Creative Commons. Vous pouvez copier, modifier des copies de cette page, dans les conditions fixées par la licence, tant que cette note apparaît clairement.