
Sécuriser son application PHP
Vous êtes ici : Accueil / Articles / Formations en PHP
La sécurité est une notion bien relative : la seule solution pour posséder un système parfaitement sécurisé est de n’avoir rien à se faire voler. Dès lors qu’un administrateur peut accéder à des données, n’importe qui est sensé pouvoir le faire, pour peu qu’il emprunte exactement le même chemin que cet administrateur. L’enjeu est donc de rendre l’accès aux données suffisamment complexe pour décourager un éventuel programme ou utilisateur malveillant.
Cette sécurité ne s’applique pas seulement aux éléments dotés d’une intention de destruction. Il peut tout simplement s’agir de se protéger des utilisateurs inexpérimentés qui pourraient créer des instabilités dans le système par une mauvaise utilisation du logiciel.
Voici quelques bonnes pratiques à respecter pour sécuriser vos applications. Attention, la sécurité dépend entièrement de l’architecture de votre application et de ses spécificités en matière de technologies utilisées. Veillez à vous documenter ses les éventuelles failles de chaque système utilisé pour les prendre en compte dans votre politique de sécurisation de l’application.
Votre environnement est source de failles
La sécurité de votre application dépend tout d’abord de son environnement. Si celui-ci est instable et comporte des failles, celles-ci seront répercutées sur votre application.
Essayez de vous rendre le plus possible indépendant de votre environnement, de sorte que si celui-ci change, l’application garde une relative sécurité.
Une bonne pratique est de noter dans un fichier les différents éléments clés de configuration pour que votre application soit sécurisée. Ainsi, en cas de changement de serveur, vous pourrez facilement effectuer les tests nécessaires.
Attention ! ne stockez pas ce fichier dans un endroit accessible par le web : la connaissance de son contenu est une grande faille de sécurité pour un utilisateur malveillant.
Prenez gardes aux inclusions
Dès lors qu’une application s’agrandit un peu, il devient nécessaire de diviser ses traitements et de les stocker dans des fichiers séparés et de les inclure en fonction des besoins. Vient alors la première faille de sécurité : l’appel de scripts n’étant pas sensés être exécutés en dehors de leur contexte. Les conséquences peuvent être très diverses, allant d’un simple message d’erreur à la destruction de vos données.
Il est donc important de rendre inaccessible les fichiers dont la finalité est d’être inclus par d’autres scripts.
La première solution est de mettre les fichiers à inclure dans un dossier parent. Si vous avez déjà réalisé des include() dans toute votre application, pas de problème : la commande suivante permet d’ajouter le dossier parent à l’include_path qui détermine les dossiers dans lesquels PHP va devoir chercher pour inclure un fichier.
set_include_path( get_include_path() . PATH_SEPARATOR . $dossier_parent );
?>
Il est également possible de spécifier directement le dossier dans le fichier php.ini :
include_path = "chemin1;chemin2"
// Sous Unix
include_path = "chemin1:chemin2"
Si vous ne disposez pas des droits nécessaires pour créer un dossier dans le répertoire parent, créez un dossier accessible par internet, mais ajoutez-y le fichier .htaccess suivant :
Une des conventions des fichiers à inclure est de les nommer avec l’extension .inc . Au niveau de PHP, les fichiers à inclure peuvent avoir n’importe quelle extension. Le problème se situe au niveau du serveur web : si vos fichiers sont accessibles par le web et que votre serveur n’est pas configuré pour considérer les fichiers avec l’extension .inc comme des scripts PHP, alors celui-ci affichera les sources sous forme de texte simple. Un des effets par exemple est l’affichage des des mots de passe de connexion à la base de données. Utilisez donc de préférence l’extension .inc.php.
Il est fréquent de vouloir n’avoir recours qu’à un seul fichier qui inclurerait tous les autres, ce qui permet d’ajouter automatiquement un header et un footer. Voici le code qu’il vaut mieux éviter :
Vous pourriez penser que cette syntaxe est sécurisée car vous précisez le dossier dans lequel se trouve le fichier à inclure.
Imaginez que l’url soit index.php ?ma_page=../../etc/password et vous aurez un bel affichage de votre fichier de d’utilisateurs si votre serveur web est mal configuré et y a accès.
Voici donc un script plus sécurisé :
echo '<head></head><body>';
// Si la variable ma_page ne contient que des caractères alphanumériques, des traits d'union ou des underscores
if( preg_match( '/^[A-Z0-9_-]+$/i', $_GET['ma_page'] ) ) {
require '/mon/dossier/' . $_GET['ma_page'] . '.php';
}
echo '</body>';
?>
Votre base de données est une cible particulièrement visée
Il est donc nécessaire de prendre les mesures suivantes et de les respecter absolument.
Tout d’abord, une première mesure qui peut paraître évidente mais qui est peu appliquée par flemmardise est l’attribution des privilèges d’utilisateur : n’utilisez pas un utilisateur avec tous les droits dans la base de données. Créez un utilisateur avec juste les prvilèges nécessaires pour les accès à la bdd par des scripts PHP.
La seconde mesure est de chiffrer les données sensibles de la base de données : ne stockez jamais une donnée sensible en clair dans la base. En ce qui concerne les mots de passe, ils ont un status particulier : il est conseillé de ne pas les chiffrer, mais de les hasher.
Sécurisez chacune des variables entrées dans une requête SQL pour éviter les attaques par injection SQL
Par exemple, le code suivant comporte une énorme faille :
// Requête sujette aux injections SQL
$requete = "SELECT * FROM users WHERE account = '{$_POST['account']}' AND password = '{$_POST['account']}'";
$res = mysql_query( $requete );
?>
Pour peu que l’utilisateur entre ’’ OR true OR password=’ dans le champ de mot de passe, et la requête SQL équivaudra à la requête suivante :
La requête précédente sera vraie quelle que soit la valeur de account. Ce genre de failles, bien qu’élémentaires, se retrouvent parfois dans des sites auxquels ont s’attend peu.
La solution est d’avoir recours à la fonction mysql_real_escape_string() qui ajoute un antislash devant chaque caractère ayant un sens au niveau de la syntaxe SQL. Dans le cas précédent, l’apostrophe sera échappée, et la requête sera sécurisée :
// Requête sécurisée
$account = mysql_real_escape_string( $_POST['account'];
$password = mysql_real_escape_string( $_POST['password'] );
$requete = "SELECT * FROM users WHERE account = '$account' AND password = '$password'";
$res = mysql_query( $requete );
?>
Enfin, pensez à fermer vos connexions à la base de données dès que vous n’en n’avez plus besoin.
Préferrez les fonctions PHP aux commandes directes
Cette recommandation s’applique aussi bien aux commandes système qu’aux requêtes à la base de données : PHP assure un minimum de sécurité dans ses fonctions et rends ainsi plus difficile les attaques par l’entrée de données à caractère malveillant comme les attaques par injection.
Par exemple, la fonction mysql_query() empêche les requêtes multiples séparées par des point-virgule. Cela évite par exemple que les hackers ajoutent une requête de suppression des données en pleins milieu de votre requête.
Les fonctions unlink(), mkdir() et toutes les fonctions de manipulation des fichiers sont préférables à l’exécution de commandes système par backsticks :
// Ajout de dossier par une syntaxe déconseillée
`mkdir $_GET['dossier']`;
?>
Le code précédent est une grosse faille car il permet les attaques par injection. En effet, l’url suivante index.php ?dossier=test ;rm -Rf / aura pour effet de créer le dossier "test" et de supprimer tous les fichiers et dossiers à partir de la racine. L’effet est plutôt déplaisant pour le webmaster.
La fonction mkdir() permet d’éviter ce genre de failles. Attention, même si une partie des failles est éliminée, il en reste d’autres comme les chemins : ces commandes ne vont pas empêcher de changer de répertoire à l’aide des ../ . Pensez donc toujours à vérifier vos données avant de les utiliser dans des traitements sensibles.
Ne vous reposez que sur la sécurité côté serveur
Partez du principe que toute vérification des données côté client tient du domaine de l’ergonomie pour faciliter la tâche de l’internaute et le guider dans le remplissage des formulaire, mais absolument pas comme une vérification suffisante : pour peu que l’utilisateur désactive le javascript, et celui-ci peut entrer n’importe quelle donnée.
Ainsi donc, chaque filtre au niveau client, s’il relève de la sécurité, devra être réeffectué côté serveur.
Conclusion
Ces mesures sont d’ordre général et s’appliquent à toute application PHP. En revanche, il existe certainement d’autres failles en fonction de l’architecture de votre application. Une bonne pratique est de partir du principe suivant : refusez tout sauf ce que vous autorisez.



