Restreindre l'accès d'un site en Javascript

Introduction

Il est courant de vouloir restreindre l'accès de certaines pages d'un site personnel. Pour cela, il y a de nombreuses possibilités. La méthode la plus fiable est celle qui consiste à faire contrôler l'accès de ses pages par le serveur les hébergeant. Ceci peut être fait soit par un dispositif spécialement conçu sur le serveur (fichier .htaccess par exemple), soit par un langage de scripts couplé à une base de données contenant les login / password afin de contrôler soit même l'accès de son site (en général avec Php/MySql sur les hébergeur gratuits).
Le problème est que certains hébergeurs, même payants, ne proposent aucune de ces solutions server-side (côté serveur). Il faut alors utiliser une méthode d'authentification client-side (côté client), ce qui n'est à priori pas possible. Cela veut en effet dire que c'est le client qui décide s'il veut ou non se connecter à certaines pages du site. Rien ne l'empêche, à priori, de vouloir accéder à toutes les pages du site. Rien ? Pas si sûr...

La solution naïve

Une solution qui vient rapidement à l'esprit des débutants en particulier (et qui m'a poussée à écrire cet article) est de créer une petite fonction en Javascript qui demande un mot de passe puis de le comparer à celui attendu. Si le bon mot de passe a été entré, la page secrète est chargée, sinon, une erreur est affichée ou bien l'utilisateur est redirigé vers une page d'erreur.
Voici un exemple de fonction typique.
function login()
{
    var password = prompt( "Veuillez entrer le mot de passe pour accéder à cette page", "" );
    // si un mot de passe a été entré
    if ( password != null )
    {
    	// on le compare à celui attendu
    	if ( password == "bravo" )
    	{
    	    // mot de passe valide, on ouvre la page secrète
    	    document.location.href = "notsecret.htm";
        }
        else
        {
            alert( "Mot de passe incorrecte!", "Erreur" );
        }
    }
}
Exemple
Cette méthode va effectivement empêcher la plupart des internautes n'ayant pas le mot de passe d'accéder à la page notsecret.htm. Mais il faut avoir à l'esprit que le langage utilisé (Javascript) est client-side, donc exécuté sur l'ordinateur de l'internaute, par son navigateur web (si le support Javascript existe et est activé). Pour exécuter cette fonction, le navigateur web doit pouvoir la lire, et si le navigateur peut la lire, l'internaute aussi.
Pour vous en convaincre, affichez les sources de cette page (Menu Affichage->Source sous Internet Explorer) et observez. Vous pouvez voir au début du code source de la page le code de la fonction d'authentification bad_login qui est utilisée ci-dessus. Placer cette fonction dans un fichier séparé ne change rien. Le nom de ce fichier est aussi contenu dans la page, afin que le navigateur web puisse la récupérer. L'internaute possédant un minimum de connaissances peut donc en faire autant (ce qui est le cas de beaucoup de monde !).
Une fois que l'intéressé a récupéré le code de la fonction d'authentification, il ne lui faut pas longtemps pour trouver deux information essentielles : le mot de passe ("bravo") et le nom de la page secrète ("notsecret.htm"). Non seulement le pirate possède votre mot de passe, mais en plus il n'en n'a pas besoin! Il lui suffit d'entrer dans la barre d'adresse de son navigateur web l'adresse de la page secrète pour y accéder directement, sans subir de contrôle d'accès.
Vous êtes peut-être surpris et scandalisé (si vous utilisez ce procédé sur votre site) de voir combien il est facile de lire votre fonction d'authentification. Mais ayez à l'esprit qu'il ne s'agit pas là d'une faille de Javascript, qui a été conçu pour fonctionner ainsi (sur le poste client demandeur de la page) et on ne peut pas faire autrement que de lui donner accès au code si on veut qu'il l'exécute. La problème se situe dans l'utilisation de Javascript pour effectuer cette tâche. Mais comme je l'ai dit en introduction, parfois, il s'agit de la seule solution disponible. Alors, comment faire cela de manière plus fiable ?

Une meilleure solution

La meilleur solution que je connaisse consiste à reporter le problème plus loin, et de le confier à HTTP. Il s'agit du protocole de communication utilisé par votre navigateur web pour récupérer des documents auprès d'un serveur qui les héberge. Ce protocole définit un certain nombre d'opérations possibles entre le client (navigateur web) et le serveur (hébergeur, par exemple, www.free.fr). Il exige entre autre que l'on connaisse le nom des documents à récupérer. Il ne permet pas de lister le contenu d'un répertoire comme le fait FTP par exemple. Si vous ne connaissez pas le nom de la page à consulter sur un site, HTTP ne vous offre aucun moyen de le savoir. Il ne permet donc pas de savoir quels sont les fichiers hébergés sur un site.
C'est sur cette particularité que la sécurité du code suivant repose.
function login()
{
    var password = prompt( "Veuillez entrer le mot de passe pour accéder à cette page", "" );
    // si un mot de passe a été entré
    if ( password != null )
    {
        // on construit un nom de page à partir du mot de passe et on l'ouvre
        document.location.href = password + ".htm";
    }
}
Exemple
A partir du code suivant, essayez maintenant de trouver le mot de passe. On ne peut pas, parce qu'il n'y est pas. Cette fonction d'authentification n'en n'est en fait pas vraiment une, puisque qu'elle n'a aucune connaissance du mot de passe attendu. A partir du mot de passe entré, elle génère un nom de page et provoque l'ouverture de celle-ci. Il y a alors deux possibilités : Ainsi, dans l'exemple ci-dessus, je protège la page secret.htm. Pour y accéder, il faut donc entrer le mot de passe secret.
Ce procédé est donc bien meilleur, mais il possède des inconvénients :
Remarques importantes

Un compromis entre les deux

Comme nous l'avons vu précédemment, la deuxième solution est plus intéressante en terme de sécurité, mais l'est moins en terme d'utilisation. La possibilité de se retrouver avec la mauvaise page ouverte et surtout d'avoir un vilain message d'erreur 404 de la page du navigateur peut poser des problèmes aux webmasters soucieux de l'esthétisme et de l'ergonomie de leur site.
C'est pourquoi j'ai eu l'idée de cette troisième solution, que je vous propose. Il s'agit de vérifier la validité du mot de passe entré non pas de manière directe comme dans le premier exemple mais de manière indirecte, au moyen d'une signature MD5.
Voici ce que cela donne.
function login()
{
    var password = prompt( "Veuillez entrer le mot de passe pour accéder à cette page", "" );
    // si un mot de passe a été entré
    if ( password != null )
    {
    	// on le compare à celui attendu
    	if ( hex_md5( password ) == "5ebe2294ecd0e0f08eab7690d2a6ee69" )
    	{
    	    // on construit un nom de page à partir du mot de passe et on l'ouvre
    	    document.location.href = password + ".htm";
        }
        else
        {
            alert( "Mot de passe incorrecte!", "Erreur" );
        }
    }
}
Exemple
La fonction hex_md5 est une fonction de hachage utilisant l'algorithme MD5. Cette fonction est issue du site de Paul Andrew Johnston, qui en est l'auteur.
A partir du mot de passe passé en paramètre elle va générer une signature de 32 caractères de long (encodage en base 64) et ce, quelque soit la longueur du mot de passe entré (1 ou 100 caractères). La propriété de cette signature est de ne pas permettre de retrouver le mot de passe qui a servi à la générer. Pour savoir à quoi comparer le mot de passe chiffré (issu de hex_md5), saisissez votre mot de passe sur le site donné, et cliquez sur le bouton MD5. Vous obtiendrez la valeur chiffrée de votre mot de passe à utiliser lors de la comparaison.
On peut ainsi, de manière simple et fiable, vérifier si le mot de passe entré est bien celui attendu, et réagir en conséquence. Le fait que le mot de passe ne soit pas accessible en clair mais en chiffré empêche l'utilisateur curieux de deviner le nom de la page secrète.
Une autre fonction est disponible : hex_sha1. Elle utilise un autre algorithme de hachage, le SHA-1, et produit une signature plus longue (40 caractères). Vous pouvez utiliser cette fonction à la place de la précédente pour encore plus de sécurité.

Limites et améliorations possibles

Ce procédé possède ses limites. Il convient assez bien dans le cadre d'un petit site personnel, afin de créer une zone dont l'accès est limité à la famille et aux amis par exemple. Il est en revanche plus difficile de maintenir une liste d'utilisateurs ayant chacun son login et son mot de passe. Une telle liste aurait de plus une taille assez limitée, car il ne faut pas oublier que le Javascript est interprété, et que l'on effectue des calculs relativement gourmands.
Une autre limite concerne le changement du mot de passe, qui est une opération assez pénible à effectuer, surtout si vous avez de nombreux fichiers protégés. Je vous conseille donc de créer un unique répertoire protégé par mot de passe, et non pas un fichier. Le mot de passe saisi permet d'accéder à ce répertoire et donc à l'ensemble de son contenu. Changer le mot de passe d'accès à l'ensemble des fichiers protégés revient à changer le nom du répertoire uniquement (ainsi que sa signature dans la fonction Javascript).

Le mot de la fin

Cet article avait pour but de sensibiliser à la sécurité des non spécialistes du Javascript (dont je fais partie). Beaucoup de monde utilise ce langage dans le cadre d'un site personnel (parfois même sans le savoir) sans bien comprendre ce que son emploi implique. Il ne s'adresse pas à des spécialistes, qui connaissent ce problème et n'utilisent pas Javascript pour authentifier les utilisateurs.
Un tel article m'a paru nécessaire suite à la rencontre répétée de cet emploi mal maîtrisé, fréquent chez un hébergeur payant connu (car ne proposant rien d'autre). J'ai ainsi vu du code exposant une vingtaine de login et mots de passe aux yeux de tous. J'ai alors réfléchi à une solution, et voilà ce que j'ai trouvé. Si vous avez besoin d'une méthode plus poussée, il faudra utiliser une solution côté serveur, et donc changer d'hébergeur.
Si vous êtes néophyte et que vous n'avez pas tout compris, envoyez-moi un mail en me précisant les points obscures, afin que j'essais d'être plus clair. Si vous êtes spécialiste et que vous avez noté des erreurs, dites le moi aussi afin que je corrige. Pour tous ceux, débutants ou confirmés, qui sont intéressés par cette technique et qui l'utilisent sur leur site, ou qui l'ont développé un peu plus (gestion de login et password par exemple), se serait sympa de me le signaler. Je mettrais un lien vers votre site avec plaisir.
A ceux-là, et à tous les autres, je souhaite une bonne navigation sur le reste de mon site, ainsi qu'ailleurs.

Pour en savior plus...

Le Javascript
Les fonctions de hachage
Choisir un bon mot de passe
Le protocole HTTP


Sommaire