Previous Up Next
Université Lille 3-Charles de GaulleUFR de Mathématiques Sciences Économiques et Sociales

Chapitre 19  Identification en PHP

Nous n'aborderons ici que l'identification gérée par le navigateur.

19.1  Préliminaires : la fonction header

La fonction header permet de spécifier une en-tête HTTP lors de l'envoi des fichiers HTML.
Reportez-vous à : http://www.w3.org/Protocols/rfc2616/rfc2616
(HTTP 1.1 Specification) pour plus d'informations sur les en-têtes HTTP.

Note : La fonction header doit être appelée avant la première balise HTML, et avant n'importe quel envoi de commande PHP.

Nous allons utiliser ici cette fonction pour demander la vérification d'une identité.

Pour cela il suffit de faire commencer votre programme PHP par la commande :
    header("WWW-Authenticate: Basic realm='private'");
qui a pour effet de faire demander (et retenir) un nom et un mot de passe par le navigateur.

Vous pouvez ainsi tester le programme élémentaire suivant : (http://www.grappa.univ-lille3.fr/polys/reseaux-DG/exemples/ident-exple01.php)
    <?php
    if (!isset($PHP_AUTH_USER) || !isset($PHP_AUTH_PW)) {
       header("WWW-Authenticate: Basic realm='private'");
    } else {
       echo "<HTML><BODY>";
       echo "les données connues sont $PHP_AUTH_USER et $PHP_AUTH_PW\n";
       echo "</BODY></HTML>";
    }
    ?>
Vous pouvez remarquer que la demande n'est faite que lors de la première exécution de la page. La seule façon, avec le programme tel qu'il est écrit, de devoir répondre à nouveau à la question est de sortir de votre navigateur (fermer toutes les fenêtres du navigateur, oui !) et de le relancer.

C'est cette propriété que nous allons utiliser pour gérer l'identification des utilisateurs.

19.2  Contrôle des mots de passe

Il ne manque qu'une seule chose (ou presque !) au programme précédent pour être parfait : tester les valeurs des variables $PHP_AUTH_USER (qui contient le nom) et $PHP_AUTH_PW (qui contient le mot de passe) pour vérifier qu'on a affaire à la bonne personne.

Une version simple pourrait ressembler à ça : (http://www.grappa.univ-lille3.fr/polys/reseaux-DG/exemples/ident-exple02.php)
    <?php
    if (($PHP_AUTH_USER=="marcel") && ($PHP_AUTH_PW=="bidule")) {
      echo "<HTML><BODY>";
      echo "Bravo, identification réussie.\n";
      echo "</BODY></HTML>";
    } else {
      header("WWW-Authenticate: Basic realm='private'");
    }
    ?>

19.3  Amélioration - plusieurs utilisateurs

Il est rare, quand l'accès à une page est contrôlée par un mot de passe, que tous les utilisateurs aient les mêmes droits.

Il faut donc pouvoir détecter l'identité de la personne concernée au moment de la saisie du mot de passe. Pour cela on donnera un mot de passe différent à chaque utilisateur. Cela nous permet d'avoir l'exemple suivant (http://www.grappa.univ-lille3.fr/polys/reseaux-DG/exemples/ident-exple03.php) dans lequel les renseignements sont rangés dans un tableau de chaînes de caractères , une chaîne par personne, présentée sous la forme « vrai nom/nom d'utilisateur/mot de passe » :
    <?php
    //la liste des informations
    $liste=array("Jean Némar/nemar/jjjj",
                 "Sophie Fonfec/fonfec/ssss",
                 "Yves Adrouille-Toultan/adrouille/yyyy");
    //création des tableaux
    for ($i=0;$i<count($liste);$i++) {
      $l=explode("/",trim($liste[$i]));
      $nom[$i]=$l[0];  //identité réelle de l'utilisateur n°i
      $user[$i]=$l[1]; //identifiant de l'utilisateur n°i sur le système
      $pass[$i]=$l[2]; //mot de passe de l'utilisateur n°i
    }
    $nbusers=count($liste);
    //contrôle de l'identité
    $ok=-1; //on démarre sans connaître l'utilisateur
    for ($i=0;$i<$nbusers;$i++) {
      if (($PHP_AUTH_USER==$user[$i]) && ($PHP_AUTH_PW==$pass[$i])) {
        //on a reconnu un utilisateur -> on garde son numéro
        $ok=$i;
      }
    }
    //si l'identification a raté, $ok contient toujours -1
    //on demande le nom et le mot de passe
    if ($ok==-1) {
      header("WWW-Authenticate: Basic realm='private'");
      return; //On notera l'utilisation de l'instruction return
              //pour sortir du programme.
    }
    //si on arrive ici, c'est que l'identification a réussi
    //et que $ok contient le numéro de l'utilisateur
    echo "<HTML><BODY>";
    echo "Bravo, identification réussie.<BR>\n";
    echo "Vous êtes <EM>nom[$ok]</EM>,\n";
    echo "votre identifiant est <EM>$user[$ok]</EM>,\n";
    echo "votre mot de passe est <EM>$pass[$ok]</EM>.<BR>\n";
    //À vous d'ajouter ici tout ce qui concerne l'utilisateur
    //...
    //...
    echo "</BODY></HTML>";
    ?>

19.4  Séparer les données du traitement

Il est tout à fait raisonnable d'imaginer qu'on va avoir besoin de changer les mots de passe, ainsi qu'ajouter des nouveaux utilisateurs ou en supprimer des anciens.

Il n'est par contre pas raisonnable du tout d'imaginer que celui qui va le faire aura envie d'aller manipuler à chaque fois le fichier du programme. (Ce n'est même d'ailleurs pas souhaitable...)

Il est donc préférable de garder ces informations dans un fichier séparé.

Qu'est-ce que cela change ? Pas grand chose : il suffit par exemple de remplacer les premières lignes :
    //la liste des informations
    $liste=array("Jean Némar/nemar/jjjj",
                 "Sophie Fonfec/fonfec/ssss",
                 "Yves Adrouille-Toultan/adrouille/yyyy");
par la lecture d'un fichier contenant les mêmes informations :
    //lire la liste des informations
    $liste=file("mettre ici le chemin d'accès au fichier");
Le reste du programme ne change pas.

Le fichier à lire sera alors un simple fichier texte, qui contiendra dans le cas présent :
    Jean Némar/nemar/jjjj
    Sophie Fonfec/fonfec/ssss
    Yves Adrouille-Toultan/adrouille/yyyy

19.5  Cacher les mots de passe

La solution précédente a un très gros inconvénient si vous placez le fichier de mots de passe n'importe où... N'oubliez pas que les pages web (HTML et PHP) sont faites pour être vues par tout le monde, depuis n'importe où. Pour permettre cela les droits d'accès de l'arborescence web sont positionnés à lisible par tous (chmod a+r*) et il ne faut surtout pas changer cela.

Ça ne posera aucun problème, tant que vous n'y entreposez pas de données confidentielles.

Mais les mots de passe, ça c'est confidentiel !

Alors, comment faire ?

Il suffit de ne pas mettre votre fichier de mot de passe dans l'arborescence web, mais de lui choisir un emplacement quelconque dont la seule obligation est d'être accessible pour l'utilisateur apache (c'est lui qui exécute les programmes PHP).

Son chemin d'accès dans l'instruction
    $liste=file("mettre ici le chemin d'accès au fichier");
devra être absolu, c'est-à-dire partir de la racine et commencer par un slash (/).

19.6  Crypter les mots de passe

Afin de ne pas rendre la vie trop facile à un éventuel pirate, il peut aussi être intéressant de crypter les mots de passe qui sont dans le fichier.

Cela se fait avec la fonction crypt.

Il n'y a pas d'algorithme de décryptage.

Mais il ne faut pas croire que cela puisse être une protection suffisante. En effet si les mots de passe, même cryptés, sont accessibles, il suffit de recopier chez soi les versions cryptées, et de les décoder tranquillement par la force brute.

Vous pourrez trouver un exemple de ce que cela signifie en exécutant le programme suivant :
http://www.grappa.univ-lille3.fr/polys/reseaux-DG/exemples/decrypt.php

Il décrypte tout mot de passe dont vous fournissez la version cryptée d'une manière totalement inintelligente, voire même plutôt bestiale : il essaie toutes les chaînes de caractères possibles (en commençant par 1 caractère, puis 2, etc.) en les énumérant systématiqument (par exemple pour 2 caractères : aa, ab, ac, ad, ae, ... , az, ba, bc, ...). Pour chaque chaîne il calcule sa version cryptée (avec la fonction crypt) et la compare à celle qu'on lui a fournie. Quand elles sont identiques, il sait qu'il vient de trouver le mot de passe.

Idiot, d'accord, mais ça marche.

Remarque : pour ne pas encombrer inutilement le serveur le temps de calcul a été limité à 2 minutes, mais cela permet quand même de trouver à coup sûr (si le serveur n'a pas trop de travail par ailleurs) n'importe quel mot de passe de 4 lettres au plus.

Et tout cela avec un programme qui n'est pas vraiment optimisé, et dans un langage qui n'est pas le plus rapide...

Il faut donc vraiment cacher les mots de passe...

D.Gonzalez (gonzalez@univ-lille3.fr) en date du th , 

Previous Up Next