La Sécurité en PHP - Partie 1
Dans mes deux derniers articles (Erreurs de style courantes, partie 1 et Erreurs de style courantes, partie 2), j’ai évoqué quelques mauvaises habitudes courantes à éviter dans vos scripts PHP parce qu’elles rendent votre code difficile à lire et plus sujet aux bogues. Dans l’article d’aujourd’hui, passons à la vitesse supérieure pour entrer dans le coeur du sujet de cette série : L’importance de la sécurité lorsqu’on travaille avec PHP.
L’importance de “penser sécurité”
Plus que l’oeil ne peut voir
La première chose à faire (hélas souvent négligée) pour éviter que des utilisateurs mal intentionnés ne compromettent vos scripts est d’imaginer les possibilités qu’ils laissent, leurs failles, au moment de les écrire. Il est important d’avoir à l’esprit les éventuelles conséquences en terme de sécurité de votre code.
Regardez l’exemple de la fonction ci-dessous écrite pour simplifier la vie d’un développeur qui écrit de nombreux fichiers texte à partir de scripts PHP :
<?php
function ecrit_texte($nomfic, $texte="") {
static $fichiers_ouverts = array();
// Si le nom du fichier est null, ferme tous les fichiers
if ($nomfic == NULL) {
foreach($fichiers_ouverts as $fr) {
fclose($fr);
}
return true;
}
$index = md5($nomfic);
if(!isset($fichiers_ouverts[$index])) {
$fichiers_ouverts[$index] = fopen($nomfic, "a+");
if(!$fichiers_ouverts[$index]) return false;
}
fputs($fichiers_ouverts[$index], $texte);
return true;
}?>
Cette fonction prend deux paramètres par défaut, le nom du fichier et le texte à écrire dans ce fichier. Cette fonction commence par vérifier si elle n’a pas ouvert ce fichier précédemment. Si c’est le cas, elle réutilise l’ancienne référence au fichier. Sinon, elle crée une nouvelle référence. Si le nom de fichier passé à la fonction est NULL, alors tous les fichiers ouverts sont fermés. Un exemple d’application est donnée plus loin.
Si le développeur écrit de nombreux fichiers texte de cette manière, cette fonction rendra son code plus clair et plus facile à comprendre. Supposons que cette fonction soit située dans un fichier distinct inclus dans les scripts nécessitant cette fonction. Voici l’un des scripts où elle est utilisée appelé citations.php:
<html><body>
<form action="<?=$_SERVER['PHP_SELF']?>" method="get">
Choisissez le type de citations :
<select name="citation" size="3">
<option value="humour">Citations humoristiques</option>
<option value="politique">Citations politiques</option>
<option value="amour">Citations romantiques</option>
</select><br />
La citation: <input type="text" name="texte_citation" size="30" />
<input type="submit" value="Enregister Citation" />
</form>
</body></html>
<?php
include_once('ecrit_texte.php');
$nomfic = "/home/web/citations/{$_GET['citation']}";
$citation_msg = $_GET['texte_citation'];
if (ecrit_texte($nomfic, $citation_msg)) {
echo "<center><hr><h2>Citation enregistrée!</h2></center>";
} else {
echo "<center><hr><h2>Erreur lors de l'écriture de la citation</h2></center>";
}
ecrit_texte(NULL);
?>
Comme vous pouvez le constater, ce développeur a utilisé la fonction ecrit_texte() créée précédemment pour développer un système permettant aux utilisateurs de soumettre leurs citations préférées qui sont ensuite enregistrées dans un fichier texte. Malheureusement, bien que ce développeur puisse ne pas le savoir, ce script pourrait permettre à un développeur mal intentionné de mettre en péril la sécurité du serveur web.
Vous devez sûrement vous gratter la tête en vous demandant comment un tel petit script tout bête peut avoir de telles conséquences en terme de séurité. Plutôt que vous demander de trouver la solution par vous-même, prenons l’exemple de l’URL suivante, en vous rappelant que le script lui-même s’appelle citations.php :
http://www.unsite.com/fun/citations.php?citation=un_autre_fichier.dat&texte_citation=nimportequoi
Que se passera-t-il lorsque cette URL sera présentée au serveur web ? Bien entendu, le script citations.php sera éxécuté ; mais plutôt que d’écrire une citation dans l’un des trois fichiers souhaités, un fichier totalement nouveau, appelé un_autre_fichier.dat, sera écrit contenant la chaîne nimportequoi. De toute évidence, ça n’est pas du tout ce qui était prévu. Ainsi, un “pirate” pourrait même être en mesure de créer un nouveau compte en accédant au fichier des mots de passe Unix en passant ../../../etc/passwd au paramètre citation (néanmoins il faudrait pour cela que le serveur web éxécute les scripts en tant que superutilisateur, et si c’est le cas vous devriez immédiatement stopper votre lecture et corriger cela tout de suite). La plus terrible conséquence envisageable est sûrement que ce script peut même être utilisé par quelqu’un pour écrire et éxécuter des scritps PHP si le répertoire /home/web/citations/ est accessible d’un navigateur. Les possibilités destructrices sont inifinies.
Il y a plusieurs parades. Si vous n’avez besoin d’écrire que quelques fichiers, vous pouvez envisager un tableau associatif pour stocker les noms des fichiers. Si l’entrée de l’utilisateur est présente dans le tableau des noms de fichiers, vous pouvez l’écrire à coup sûr. Une autre option consiste à supprimer tous les caractères non-alphanumériques pour vous assurer qu’il n’y a pas de séparateurs de répertoire. Une autre idée, enfin, consiste à vérifier l’extension des fichiers pour être sûr qu’ils ne seront pas éxécutés par le serveur web.
L’idée derrière tout cela est simple. En tant que développeur, vous devez être conscient de tout ce que vos scripts peuvent faire au-delà de l’utilisation “normale” pour laquelle ils ont été écrits. Que se passera-t-il si une donnée invalide est saisie dans un champ d’un formulaire ? Y-a-t’il un moyen pour une personne mal intentionnée de détourner votre script pour qu’il agisse de façon inattendue ? Quelles mesures sont prises pour éviter ce type d’attaque ? Votre serveur web et ses scripts PHP sont aussi sécurisés que le plus faible d’entre eux, il est donc important d’identifier le maillon faible avant qu’un autre ne le trouve pour vous.
Erreurs courantes relatives à la sécurité
Pour vous donnez quelques indications, voici une petie liste non exhaustive de failles dans le code ou l’administration qui peuvent compromettre la sécurité :
- Erreur 1. Faire confiance aux donnéesTout au long de cette série sur la sécurité et PHP, je reviendrai sur ce thème. Ne faites jamais confiance à une donnée fournie par une source extérieure. Que ce soit une donnée saisie par un utilisateur dans un formulaire, un fichier du système de fichiers, une variable d’environnement, rien ne doit être pris pour argent comptant. Toute entrée fournie par un utilisateur doit être validée et formatée pour être certain qu’elle est sûre.
- Erreur 2. Stocker des données sensibles dans l’arborescence webToute donnée sensible doit être stockée dans un fichier distinct dans un répertoire inaccessible via une requête au serveur web. Quand cette donnée sensible est nécessaire elle peut être incluse dans le script PHP au moyen d’une instruction include ou require.
- Erreur 3. Ne pas implémenter les précautions recommandées relatives à la sécuritéLe manuel PHP contient un chapitre complet sur la sécurité et les précautions à prendre lorsqu’on code des scripts. Le manuel présente (presque) systématiquement le risque de chaque fonction au cas par cas et comment minimiser ce risque. Je le rapelle, les pirates comptent surtout sur la négligence des développeurs et des administrateurs système en terme de sécurité pour avoir accès à leurs systèmes. Tenir compte sérieusement de ses avertissements c’est diminuer de façon notable la probabilité qu’une personne mal intentionnée puisse causer de réels dégâts dans votre système.
D’autres informations sur la sécurité
Je ne pourrai jamais insister suffisamment sur l’absolue nécessité de “penser sécurité” pour protéger vos serveurs de personnes mal intentionnées. Vous devriez regarder vos scripts sous une nouvelle lumière dorénavant. Avec un peu d’expérience, vous percevrez bientôt les failles potentielles avant même d’écrire le code correspondant. Le prochain article traitera de quelques autres failles courantes des scripts PHP et les étapes à suivre pour que vous, en tant que développeur, puissiez minimiser ces risques.

Textes originaux en anglais sur O’Reilly : PHP security, Part 1 par John Coggeshall
Chargement
Commentaires récents