Sécuriser son site en PHP

L'auteur

Site personnel

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

I. Introduction

Cet article a pour but de vous initier à la sécurisation de pages grâce à PHP. Vous découvrirez ici comment protéger des parties de votre site en utilisant différentes techniques de sécurité. Si vous ne possédez que peu de connaissances sur la sécurité réseau, cet article vous permettra de découvrir comment vous protéger, mais aussi comment protéger vos utilisateurs des différents abus sur internet. Si vous ne connaissez pas du tout PHP, vous devriez commencer par lire un cours pour vous familiariser à PHP. Les fonctions présentées dans cet article sont aussi détaillées que possible, cependant, leur compréhension vous sera difficile si vous ne connaissez pas un minimum PHP. Cet article n'a pas la prétention de vous enseigner comment mettre en place une sécurité absolue. L'auteur tente de vous expliquer comment mettre en place la meilleure sécurité possible, cependant, aucune garantie n'est fournie quant à l'inviolabilité de ce système.

Vous pouvez télécharger le projet complet en annexe.

Je tiens également à remercier Rmotte et Jérôme qui ont pris le temps de relire cet article.

II. Un cours rapide sur la sécurité

Lorsque vous faites transiter des données sur internet, celles-ci peuvent être interceptées et lues. S'il s'agit simplement des pages HTML de votre site cela n'a pas beaucoup d'importance. Cela peut poser plus de problèmes s'il s'agit de données sensibles, comme les mots de passe par exemple. Il existe plusieurs solutions pour se prémunir de ce type de problème.

La première consiste à utiliser un cryptage SSL pour le transfert de vos données. De cette manière les données qui transitent ne peuvent pas être interceptées. Cette technologie est réputée sûre. Toutefois, il faut garder à l'esprit que les clés utilisées par SSL sont actuellement de 128 bits. La taille des clés reste donc relativement faible. Une telle sécurité garantit la sécurisation de vos données face à des particuliers et durant un temps raisonnable. Si vous devez protéger vos données durant un temps très long, cette sécurité ne sera probablement pas suffisante. Il est cependant très rare que vous ayez besoin d'une sécurisation plus forte. Le problème est que très peu d'hébergeurs proposent un accès à la technologie SSL. Il vous faudra donc trouver une autre solution.

La deuxième solution consiste à crypter localement les données sensibles avant de les envoyer. Ici, nous considérerons que le contenu même de vos pages n'est pas « top confidentiel » et qu'il peut transiter sans être crypté. Seuls les mots de passe seront donc cryptés. Notez tout de même que l'interception de pages « à la volée » est difficile et que les risques restent faibles. Cependant, si le contenu de vos pages est réellement très important, vous devez impérativement utiliser SSL. La solution pour crypter des mots de passe consiste à réaliser un « hash » (ou signature) du mot de passe. Le hachage est une technologie de cryptage à sens unique : à partir d'un mot, il est facile d'obtenir sa signature (le hash). L'inverse est pratiquement impossible. C'est donc seulement la signature du mot de passe qui transitera sur le réseau, et non pas le mot de passe lui-même. Notez toutefois que si une personne parvient à intercepter la signature de votre mot de passe, elle aura accès au site, car elle pourra alors renvoyer cette signature pour se connecter. Cependant, elle ne pourra pas connaître votre mot de passe. Même si l'accès du site est violé, votre mot de passe ne sera pas compromis, ce qui est un gain de sécurité énorme (si vous utilisez ce mot de passe pour d'autres services par exemple). L'utilisation du hachage des mots de passe ne rendra donc pas plus sûr l'accès à votre site. En effet, il n'est pas plus difficile d'intercepter une signature qu'un mot de passe si les transmissions se font en clair. Pour empêcher cela, vous devez utiliser une technologie comme SSL. Cependant, la sécurité offerte à l'utilisateur est bien meilleure dans le sens ou son mot de passe restera protégé.

Nous utiliserons ici MD5. MD5 est très pratique et de nombreuses implémentations de cet algorithme sont disponibles dans pratiquement tous les langages. De plus, MD5 est utilisable librement. Le niveau de sécurité offert par MD5 est suffisant pour quasiment toutes les applications. Cependant, si vous désirez un niveau de sécurité très élevé, optez plutôt pour SHA qui est réputé plus sûr. Si vous désirez implémenter la même technique que celle décrite dans cet article avec SHA, il vous faudra trouver une implémentation Javascript de SHA (PHP gère SHA en natif). Le principe restera cependant exactement le même et l'utilisation de SHA au lieu de MD5 ne présentera aucunes difficulté particulière.

Le but de cette initiation à la sécurité (et à la cryptographie) est de vous faire prendre conscience des risques de sécurité qui existent dans la méthode que nous allons utiliser. La méthode que nous allons utiliser n'est pas fiable a 100 %, soyez en conscient. Il est possible de passer outre ce type de sécurité tout simplement, car les transmissions peuvent être interceptées, car elles sont faites en clair. Cependant, le niveau de sécurité proposé ici est suffisant pour quasiment toutes les applications personnelles. Passer outre ce type de sécurité n'est pas impossible mais reste pour le moins difficile et demande du temps et énormément de maîtrise. À moins que vous ne deviez protéger des données militaires ou bancaires (ce qui n'est probablement pas le cas si vous lisez cet article), ce système vous conviendra.

III. Présentation du projet

Le projet se présente sous la forme de 5 fichiers principaux.

Image non disponible

Figure 1 - Arborescence du projet

La page login.php permet à l'utilisateur d'entrer son login et son mot de passe. Cette page utilise le fichier de script login.js (qui n'est pas représenté ici). C'est dans ce fichier que sont inclus les scripts javascripts nécessaires (et notamment MD5). Si vous le désirez-vous pouvez inclure directement ces scripts dans votre page.

La page logout.php doit être appelée si l'utilisateur désire se déconnecter.

La page auth-config.php contient les informations de configuration du système.

La page auth.php est appelée par login.php lorsqu'un utilisateur se connecte. C'est cette page qui vérifie si l'utilisateur est autorisé ou non à se connecter. Pour cela, vous pouvez utiliser par exemple une base de données.

La page authcheck.php doit être incluse en début de chaque page que vous désirez protéger. Cette page vérifie si l'utilisateur s'est préalablement identifié. Si ce n'est pas le cas, l'utilisateur sera redirigé vers la page login.php.

Dans cet exemple nous n'avons créé qu'une page protégée, nommée page.php. Si vous désirez en ajouter, il suffit d'inclure authcheck.php en début de vos pages.

IV. Les sessions en PHP

Lorsqu'un utilisateur navigue sur un site, il est difficile de passer des informations de page en page. PHP permet de faire cela grâce aux sessions. La création d'une session permet d'assigner des valeurs à des variables, puis de faire passer ces valeurs aux pages que l'utilisateur verra ensuite.

Lorsque vous créez une session, PHP renvoie au navigateur un cookie de session. C'est un identifiant que le navigateur renverra à chaque page visitée. Les variables que vous utilisez sont stockées sur le serveur. En fonction de l'identifiant qu'il reçoit, le serveur détermine quelle session est associée avec l'utilisateur et passe les variables correspondantes au script.

En principe, les identifiants de session ne sont pas stockés sur le disque, ou seulement temporairement. La fermeture du navigateur entraîne généralement la destruction de ces identifiants. Un utilisateur ne peut donc pas se reconnecter avec la même session s'il ferme son navigateur. Toutefois, tous les navigateurs ne procèdent pas comme ça. Il faut donc supposer qu'il est possible à un utilisateur de récupérer la même session après avoir fermé son navigateur. Si un utilisateur se connecte depuis un ordinateur public, une personne peut donc utiliser sa session après qu'il soit parti, pour avoir accès au site. La fonction de « logout » permet d'éviter cela. Elle détruit explicitement la session. Si le navigateur tente d'utiliser le même identifiant de session, cela ne fonctionnera pas. Étant donné que beaucoup d'utilisateurs ne se déconnectent pas, nous introduirons ici un système de « timeout », qui permet de détruire la session après un certain temps d'inactivité de l'utilisateur.

Le principe de fonctionnement des sessions est totalement transparent pour vos scripts. Vous n'avez donc pas besoin de comprendre le fonctionnement pratique des sessions. Cependant, cela peut vous aider à prévenir les abus qui pourraient être réalisés, par exemple la récupération des identifiants de session.

Pour ouvrir une session, vous devez utiliser la fonction session_start(). Vous pouvez ensuite créer des variables de session grâce au tableau super-global $_SESSION. Pour accéder aux variables de session, utilisez le même tableau super-global, $_SESSION. Pour détruire une variable de la session, utilisez la fonction unset(). Pour tester si une variable est définie, utilisez la fonction isset().

Pour qu'un script puisse avoir accès aux données de session, vous devez toujours utiliser session_start(). Vous devez appeler cette fonction pour chaque page voulant utiliser la session. Vous pouvez ensuite manipuler les variables enregistrées comme des variables classiques. Pour détruire la session en cours utilisez session_destroy(). Attention, vous devez vous-même désallouer les variables de session.

Vous ne devez jamais présupposer l'existence de variables de session. En effet, l'utilisateur peut démarrer son navigateur et taper directement l'URL d'une page à laquelle il ne devrait normalement pas avoir accès. Dans ce cas, aucune variable de session ne sera définie. Même si cette action est « illégale » et ne devrait pas se produire si l'utilisateur respecte le fonctionnement de votre site, cela peut se produire et vous devez en être conscient. Ne présupposez donc pas les pages visitées avant par un utilisateur quelconque.

Exemple :

 
Sélectionnez
session_start();
$_SESSION['variable']="valeur";
unset($_SESSION['variable']);
session_destroy();

Code 1 - Utilisation des sessions

Si vous désirez plus d'informations sur la manipulation des sessions en PHP, reportez-vous au manuel de PHP.

V. Description détaillée des pages

login.php

 
Sélectionnez
<html> 
<head> 
<title>Login Page</title> 
<meta http-equiv='Content-Type' content='text/html; charset=iso-8859-1' /> 
<script language="javascript" type="text/javascript" src="login.js"></script> 
</head> 
<body> 

<form id='log' method='post' action='templates/auth.php' onsubmit='javascript:su 
bmit_pass();'> 
<input type='hidden' name='md5' /> 
<table align='center'> 
<tr><td>Login</td><td><input name='login' /></td></tr> 
<tr><td>Mot de passe</td><td><input type='password' name='passwd' /></td></tr> 
<tr><td colspan='2' align='center'><input type='submit' value='Login !' /></td>< 
/tr> 
</table> 
</form> 

</body> 

Code 2 - login.php

Cette page comprend un formulaire permettant à l'utilisateur d'entrer son login et son mot de passe. Le champ caché MD5 contiendra la signature du mot de passe. C'est ce champ qui sera transmis (et non pas le mot de passe). Notez le script appelé par l'événement « onSubmit ». Ce script sera responsable du calcul du MD5.

La description du script utilisé pour le calcul du MD5 ne présente aucun intérêt, sachez seulement qu'il calcule le MD5 d'une chaîne de caractères. Étudions plutôt le script « submit_pass ».

 
Sélectionnez
function submit_pass()
{
  pass=document.forms['log'].passwd.value;
  document.forms['log'].passwd.value="";
  buf=MD5(pass);
  document.forms['log'].md5.value=buf;

  return true;
}

Code 3 - submit_pass()

Ce script récupère le mot de passe entré, calcul le MD5 puis place le MD5 dans le champ caché nommé MD5 du formulaire d'authentification. Il efface ensuite la valeur du mot de passe de manière à ce que celui-ci ne soit pas transmis. Le formulaire est ensuite validé et les informations sont envoyées à la page auth.php par la méthode POST. La méthode POST offre plus de sécurité que la méthode GET, car les identifiants ne sont pas stockés dans les URLs qui sont parfois gardées en mémoire. Il est donc impossible de retrouver les identifiants par l'historique.

auth.php

 
Sélectionnez
<?php 
function CheckUser($login,$md5) 
{ 
  if($login=="user" && $md5=="ab4f63f9ac65152575886860dde480a1"// MD5 de azert 
y 
    return true; 
  return false; 
} 
?> 
<?php 
if(!isset($_POST['md5'])) 
{ 
  header("Location: ../login.php"); 
  die(); 
} 
$md5=$_POST['md5']; 

if(!isset($_POST['login'])) 
{ 
  header("Location: ../login.php"); 
  die(); 
} 
$login=$_POST['login']; 

if(!CheckUser($login,$md5)) 
{ 
  header("Location: ../login.php"); 
  die(); 
} 

session_start(); 

$_SESSION['last_access']=time(); 
$_SESSION['ipaddr']=$_SERVER['REMOTE_ADDR']; 
$_SESSION['user']=$login; 

header("Location: ../page.php"); 
?> 

Code 4 - auth.php

La fonction CheckUser() vérifie si l'utilisateur à accès ou non au service proposé. Ici, nous avons entré « manuellement » un utilisateur nommé « user » avec pour mot de passe « azerty » (ce qui n'est pas un très bon choix en matière de sécurité!). Si vous le désirez, vous pouvez ici accéder à une base de données ou tout autre système vous permettant de savoir si l'utilisateur est autorisé ou non à avoir accès au service. Notez qu'il vous faudra stocker le MD5 des mots de passe et non les mots de passe eux-mêmes. En effet, le stockage des mots de passe est très dangereux, car si la base de données est compromise, les mots de passe de milliers d'utilisateurs se trouveront compromis. S'ils utilisent ce mot de passe pour d'autres services, cela peut poser énormément de problème. Le stockage des MD5 règle donc ce problème. La fonction CheckUser() retourne simplement true ou false.

Nous récupérons ensuite les variables MD5 et login grâce au tableau superglobal $_POST. Si ces valeurs ne nous ont pas été fournies, l'utilisateur est redirigé vers la page login.php.

L'identité de l'utilisateur est ensuite vérifiée grâce à la fonction CheckUser(). Si l'utilisateur n'a pas accès au service, il est redirigé vers la page login.php. Si l'accès lui est autorisé, alors la session peut être créée.

Les variables de session utilisées sont :

last_access qui permettra de mettre en place un système de timeout. Si l'utilisateur est inactif pendant un temps donné, sa session sera fermée. Le principe de timeout est essentiel au niveau sécurité. En effet, de nombreuses personnes oublient de se déconnecter. Le système de timeout permet de palier à ce problème. Après un certain temps d'inactivité, la session sera considérée comme expirée et l'utilisateur devra se réidentifier.

ipaddr permet de stocker l'adresse IP de la personne se connectant. Cette adresse sera comparée à chaque accès avec l'adresse du client. Ceci permet d'éviter le vol de sessions. En effet, une technique possible pour usurper l'accès à un site consiste à attendre qu'un utilisateur se log, puis récupérer son cookie de session et l'utiliser pour naviguer. Cette technique est rendue impossible par cette vérification.

user est simplement le nom de l'utilisateur. Cette variable n'est d'aucune utilité au niveau sécurité. Il est cependant pratique de pouvoir connaître le nom de l'utilisateur connecté. Vos pages peuvent donc utiliser cette variable.

authcheck.php

 
Sélectionnez
<?php 
session_start(); 

if(!isset($_SESSION['last_access']|| !isset($_SESSION['ipaddr']|| !isset($_S 
ESSION['user'])) 
{ 
  $_SESSION=array(); 
  session_destroy(); 
  header("Location: login.php"); 
  die(); 
} 

if(time()-$_SESSION['last_access']>$session_timeout) 
{ 
  $_SESSION=array(); 
  session_destroy(); 
  header("Location: login.php"); 
  die(); 
} 
if($_SERVER['REMOTE_ADDR']!=$_SESSION['ipaddr']) 
{ 
  $_SESSION=array(); 
  session_destroy(); 
  header("Location: login.php"); 
  die(); 
} 
$_SESSION['last_access']=time(); 
?> 

Code 5 - authcheck.php

Cette page vérifie l'identité de la personne connectée. Elle doit être incluse en début de chaque page à protéger. Tout d'abord, il faut vérifier si les variables de sessions sont présentes. Si elles ne le sont pas, l'utilisateur n'est pas identifié et il doit le faire. On le redirige donc vers la page login.php.

On vérifie ensuite l'ancienneté de la session. Si elle est expirée, on la ferme et on redirige l'utilisateur vers la page login.php.

Enfin, la vérification de la concordance des adresses IP est faite. Si les adresses ne concordent pas, l'utilisateur est redirigé vers la page login.php.

Si l'utilisateur a passé tous ces tests, c'est qu'il peut accéder aux données. On met donc à jour la variable last_access.

logout.php :

 
Sélectionnez
<?php 
session_start(); 

$_SESSION=array(); 
session_destroy(); 
header("Location: login.php"); 
die(); 

?> 

Code 6 - logout.php

Cette page permet à l'utilisateur de se déconnecter. Elle ferme la session et redirige l'utilisateur vers la page login.php.

VI. Conclusion

Ce système est classique en matière de sécurité sur internet. Il offre une sécurité correcte. On peut considérer que ce système est inviolable pour tout utilisateur « normal ». Cependant, une personne expérimentée disposant de moyens d'écoute du réseau peut parvenir à passer outre cette protection. Soyez en conscients si vous protégez des données importantes.

Le point fort de ce système est la protection des mots de passe. Comme seuls les MD5 des mots de passe transitent sur le réseau, la protection des mots de passe des utilisateurs est toujours garantie, ce qui constitue un très bon point au niveau sécurité.

L'utilisation de timeouts de sessions courts (quelques minutes) est également une très bonne idée. Comme énormément de personnes oublient de se déconnecter, cela permet d'accroître la sécurité. De plus, si l'utilisateur est actif, il ne sera même pas conscient de la présence de timeouts.

Un autre avantage à la mise en place de ce système est qu'il est facile à mettre en œuvre et ne nécessite que la présence de PHP. De plus, l'ajout de nouvelles pages protégées est particulièrement simple.

D'autre part l'utilisation de cookies de session au lieu de cookies permet une sécurité accrue. En effet, aucune information sensible n'est stockée sur la machine du client. Ce système peut donc être utilisé sur des machines publiques.

VII. Annexe

MD5 (Message Digest) : http://www.rsasecurity.com/rsalabs/

SHA (Secure Hash Algorithme) : http://www.faqs.org/rfcs/rfc3174.html

Documentation sur PHP : http://www.php.net/docs.php

Un excellent article sur la sécurité avec PHP : http://thierrylhomme.developpez.com/php/php_secure/

Télécharger le projet : projet.zip (4 Ko)

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2013 Bob. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.