Pour partager cette vidéo sur les réseaux sociaux ou sur un site, voici son url :
Sujets que vous pourriez aussi aimer :Connexion sécurisée Anti-Keylogger en Javascript
Dans cette
formation Javascript, nous proposons de bâtir un système d'
authentification sécurisée anti-Keylogger, comme le proposent les banques, afin de
protéger la saisie du mot de passe pour accéder aux comptes en ligne. Un
Keylogger est un
programme malveillant qui enregistre les touches du clavier au fur et à mesure de la frappe de l'internaute. Ces informations sont retournées aux hackeurs avec l'Url de la page concernée. Dès lors, ils peuvent pirater les informations bancaires et se servir.
La solution consiste à imposer la saisie du mot de passe par clics sur des images ou boutons numérotés, qui se positionnent aléatoirement à chaque nouvelle connexion. C'est ce qu'illustre l'application finalisée sur la capture. Seul l'oeil humain peut repérer sans ambigüité la position des numéros pour reconstruire le
mot de passe afin de valider l'
identification.
Sources et présentation du concept
Pour concentrer notre attention sur la partie du
développement en Javascript, nous proposons de récupérer les sources qui offrent la structure de la
page Web de connexion.
La décompression conduit au fichier de la
page Web principale à la racine, accompagné de ses ressources externes dans les sous dossiers.
- Double cliquer sur le sous dossier js pour l'ouvrir,
- Puis, cliquer avec le bouton droit de la souris sur le fichier de script : paire_id.js,
- Dans le menu contextuel, choisir de l'ouvrir avec un éditeur tel que le Notepad,
Ce script externe propose une seule fonction retournant la paire identifiant et mot passe permettant de réussir l'authentification, selon le code suivant :
functionid_mp()
{
var paire='bonbache|622551';
return paire;
}
Bien sûr, il s'agit ici d'une simulation. Jamais une application en production ne devra livrer des renseignements aussi sensibles sans les protéger. Le
code Javascript doit se charger du positionnement aléatoire des numéros et de récolter les informations d'identification saisies. C'est le développement que nous devons réaliser ici. Ensuite, il doit transmettre ces informations à un
code serveur Php qui pourra interroger la base de données, afin de valider ou non la correspondance. Mais comme il n'est pas question de code serveur ici, nous simulons le principe de transmission des informations, par le biais d'un
script externe.
- A la racine du dossier de décompression, double cliquer sur le fichier identification-securisee-cpt.html pour l'ouvrir dans un navigateur par défaut,
Comme vous le constatez, la
page Web offre en effet la
structure Html principale. Les boutons numérotés sont absents. Et les fonctionnalités de contrôle de saisie et de validation sont inopérantes. Il s'agit du
code Javascript à bâtir.
L'objectif est de positionner aléatoirement 10 boutons, numérotés de 0 à 9, dans les cases de la grille située sur la gauche. Cette grille est réalisée par l'imbrication de calques, soit de
balises Html Div. Au clic sur chaque bouton, le numéro correspondant doit s'ajouter à la suite dans la zone du
mot de passe crypté. Ce
contrôle Html de type Password est d'ailleurs verrouillé à la saisie pour protéger la connexion contre les
Keyloggers. L'identifiant quant à lui doit être tapé au clavier. Un clic sur le
bouton Valider doit déclencher un autre code Javascript capable de comparer cette paire avec les données d'
authentification. Si le test échoue, la connexion est refusée. Dans le cas contraire, elle est autorisée et les données sensibles ont été protégées.
- A la racine du dossier de décompression, cliquer avec le bouton droit de la souris sur le fichier de la page Web identification-securisee-cpt.html,
- Dans le menu contextuel, choisir de l'ouvrir avec un éditeur tel que le Notepad ++,
Dans la section Head du code Html, vous notez la référence au script externe :
...
<meta http-equiv="content-language" content="fr" />
<link href='styles/mef.css' rel='stylesheet' type='text/css' />
<script language="Javascript" src="js/paire_id.js"></script>
</head>
<body>
...
Il est ainsi chargé en même temps que la page Web de connexion. Donc sa
fonction id_mp peut être appelée par son nom, pour réaliser la comparaison des informations en Javascript.
Entre les lignes 50 et 77 pour un éditeur Notepad, figure l'imbrication des calques ayant permis la construction de la grille notamment. On y trouve aussi les contrôles Html des boutons qui devront déclencher le code des fonctions au clic.
...
<div class="colonne" id="liste">
<div id="grille">
<div class="case" id="case0"></div>
<div class="case" id="case1"></div>
<div class="case" id="case2"></div>
<div class="case" id="case3"></div>
<div class="case" id="case4"></div>
<div class="case" id="case5"></div>
<div class="case" id="case6"></div>
<div class="case" id="case7"></div>
<div class="case" id="case8"></div>
<div class="case" id="case9"></div>
<div class="case" id="case10"></div>
<div class="case" id="case11"></div>
<div class="case" id="case12"></div>
<div class="case" id="case13"></div>
<div class="case" id="case14"></div>
<div class="case" id="case15"></div>
</div>
<input type="text" id="identifiant" maxlength="10" value="Votre identifiant" onClick="init_saisie('1')" onMouseOut="init_saisie('2')"/>
<input type="password" id="motPasse" maxlength="6" value="" readOnly />
<input type="button" class="bouton" value="Valider" />
<input type="button" class="bouton" value="Generer" /><br />
<span style="font-size:14px;font-weight:normal;">Paire à reproduire :
<strong>bonbache|631975</strong></span>
</div>
...
Vous constatez que chaque case de la grille est judicieusement nommée grâce à son
attribut Id. Chaque calque est en effet préfixé de l'information statique case, associée à un numéro incrémenté. Cette désignation facilitera grandement le développement pour
placer aléatoirement les boutons en fonction du nombre généré.
Enfin, en bas du code Html, vous notez la présence d'une
section de Script Javascript. La
fonction init_saisie est déjà présente. Elle est appelée par la zone de saisie de l'identifiant sur deux événements :
OnClick et
OnMouseOut. Elle permet tout simplement de vider la zone ou de restituer l'information par défaut, pour guider l'utilisateur.
Placement aléatoire des numéros d'identification
La
formation Javascript pour générer des nombres aléatoires nous avait appris à maîtriser cette technique. La grille est constituée de 16 cases identifiées par un nom affublé d'un indice variant de 0 à 15. Nous devons donc générer un
nombre aléatoire entier compris entre ces bornes. Cette
génération aléatoire doit être reproduite 10 fois, pour chacun des boutons numérotés à disposer indépendamment. Nous devons donc nous assurer que le même nombre ne ressorte jamais deux fois, pour que ces boutons ne se chevauchent pas.
En bas de la page Html, dans la section du script, un appel anticipé de fonction existe :
generation(). Mais cette fonction n'existe pas encore. Nous devons la créer. C'est elle, qui par
génération aléatoire, doit positionner les boutons permettant d'inscrire le mot de passe.
- Juste après cette ligne, créer la fonction generation comme suit :
function generation()
{
}
Comme son appel intervient en début de
script, en dehors de toute fonction, son
code Javascript sera exécuté en même temps que la page se charge.
Comme toujours, nous devons commencer par
déclarer les variables nécessaires au traitement.
- Dans les bornes de la fonction, ajouter les déclarations et l'instruction suivantes :
var nb_alea;
var test = true; var chaine = "";
purger();
La
variable nb_alea doit permettre de stocker le nouveau
nombre aléatoire généré, à chaque passage dans la boucle. 10 boutons sont à placer, donc dix nombres aléatoires compris entre les bornes 0 et 15, doivent être générés sans doublons. La
variable test est déclarée comme un booléen et initialisée Ã
true. Elle considère par défaut que le
nombre aléatoire existe déjà , pour forcer la régénération. A chaque fois qu'un
nombre aléatoire inédit sera produit, elle devra être affectée Ã
False pour permettre à la boucle de traiter le bouton suivant. Justement, la
variable chaine doit servir à concaténer tous les
nombres aléatoires déjà produits, afin de réaliser cette vérification.
Enfin, nous appelons la
fonction purger qui n'existe pas encore. Sa mission est de purger la grille des potentiels précédents boutons et de vider les zones de saisie. En effet, la
fonction generation sera à terme appelée au clic sur le bouton Générer. L'objectif est de permettre à l'utilisateur de tout recommencer s'il s'est trompé. Avant de poursuivre le développement de la
fonction generation, nous devons donc coder la
fonction purger.
- Après la fonction generation, créer la fonction purger, comme suit :
function purger()
{
for (var i=0;i<16;i++)
{
document.getElementById('case' + i).innerHTML = "";
}
document.getElementById('identifiant').value = "Votre identifiant";
document.getElementById('motPasse').value = "";
}
Nous initialisons une
boucle de traitement pour parcourir l'ensemble des calques de la grille, numérotés de 0 à 15. A chaque passage dans la boucle, nous accédons à chacun d'entre eux, grâce à la
méthode getElementById de l'
objet Javascript document. Nous passons à cette méthode l'identifiant fixe ('case') concaténé à la valeur de la variable de boucle, qui varie bien de 0 à 15, soit les 16 calques. Après la boucle, toujours avec la
méthode getElementById pour désigner un contrôle Html, nous accédons aux deux zones de saisie. Celle de l'identifiant est réinitialisée à sa valeur informative par défaut, tandis que celle du mot de passe est vidée.
Il s'agit maintenant de reprendre le développement de la
fonction generation. Nous devons passer en revue l'ensemble des 10 boutons.
- A la suite du code de la fonction generation, après l'appel de la fonction purger, créer la boucle for suivante :
for (var i=0;i<10;i++)
{
}
10 passages seront donc réalisés par cette
boucle. A l'intérieur de ce traitement récursif, nous devons générer un
nombre aléatoire pour placer le bouton ainsi désigné dans le
calque Html correspondant. Mais cette action ne vaut que si le nombre aléatoire n'a pas encore été généré. Et c'est la variable test qui l'indique. Nous devons donc l'exploiter en critère d'une
boucle While. Ainsi elle ordonnera la régénération, tant que le nombre existe déjà .
- Dans les bornes de la boucle for, ajouter les lignes suivantes :
while (test==true)
{
nb_alea = Math.floor(Math.random()*16);
}
Comme prévu, nous devons désormais nous assurer que ce nombre aléatoire n'a pas déjà été produit. S'il existe déjà , il doit être regénéré. Comme le test vaut toujours
true, cette action doit se répéter jusqu'à produire un nombre nouveau. Dans le cas contraire, le
code Html du bouton désigné par la
variable i doit être écrit dans le
calque Html désigné par la
variable nb_alea. Ce nouveau nombre doit être mémorisé par concaténation dans la
variable chaine. Et puis, le booléen doit être basculé Ã
False, pour sortir de la
boucle While et passer au bouton suivant, grâce à la reprise de la
boucle For.
- En conséquence, à la suite du code de la boucle While, ajouter les instructions suivantes :
if(chaine.indexOf("-" + nb_alea + "-")>-1)
nb_alea = Math.floor(Math.random()*16);
else
{
document.getElementById('case' + nb_alea).innerHTML = "<input type='button' class='btn' value='" + i + "' onClick='document.getElementById(\"motPasse\").value += " + i +"' />";
chaine += "-" + nb_alea + "-";
test=false;
}
C'est la
méthode indexOf appliquée sur une variable de type chaîne de caractères, qui renvoie la position de l'occurrence qui lui est passée en paramètre. Nous l'avions exploitée dans la
formation Javascript consistant à récupérer les paramètres d'Url. Elle permettait de renseigner sur la position du point d'interrogation (?), à partir duquel les informations étaient passées. Ici, nous cherchons la position de l'occurrence : "-" + nb_alea + "-". A chaque passage en effet, nous concaténerons le nouveau nombre, encadré de tirets pour le reconnaître sans ambiguïté. Si la
méthode indexOf ne retourne pas la valeur -1, cela signifie que le nombre existe déjà . En conséquence nous le régénérons.
Dans le cas contraire (else), grâce à la
propriété innerHTML d'un
contrôle Div, nous reconstruisons le
code Html, du calque passé en paramètre de la
méthode getElementById. Il s'agit du calque dont le suffixe correspond au nouveau
nombre aléatoire généré entre bornes. Le code Html est celui d'un bouton sur lequel nous inscrivons le numéro (value='" + i + "') correspondant à la valeur en cours dans la
boucle For. De même, nous générons son événement à la volée qui consiste à inscrire ce numéro à la suite (-=), dans le contrôle de
type Password. Notez l'emploi du caractère d'échappement (\) pour pouvoir désigner l'identifiant du contrôle dans la méthode getElementById (\"motPasse\"). En effet, l'
instruction Html est déjà encadrée de doubles côtes. L'
instruction de l'événement onClick alterne entre simples côtes. Ni l'une ni l'autre ne peuvent donc être utilisées. Et c'est l'antislah qui permet de ne pas briser la construction de cette chaîne statique. Enfin, nous mémorisons ce nouveau nombre aléatoire à la suite (chaine += "-" + nb_alea + "-"). L'objectif est qu'il ne soit pas reproduit lors du prochain traitement. Puis, nous affectons la
variable booléenne à false (test=false), pour pouvoir sortir de la
boucle While et reprendre l'énumération des boutons dans la
boucle For.
Un réglage est nécessaire avant de reprendre l'incrémentation de la
boucle For. A la sorite de la
boucle While, la
variable booléenne doit être réaffectée Ã
True. Si ce n'est pas le cas, le
critère de la boucle While imbriquée ne sera jamais vérifié. En conséquence plus aucun
nombre aléatoire ne sera généré.
- Après la fermeture de la boucle While et avant la fermeture de la boucle For, ajouter l'instruction suivante :
test=true;
Notre code peut d'ores et déjà être testé au chargement de la page Web.
- Enregistrer les modifications (CTRL + S) et basculer sur le navigateur Internet,
- Rafraîchir la page Html à l'aide de la touche F5 du clavier,
Comme vous le constatez et comme l'illustre la capture ci-dessous, les 10 boutons sont bien présents et sont placés aléatoirement, dans les 16 cases qui leur sont proposées. Si vous cliquez sur ces derniers, les numéros encryptés se consolident dans le
contrôle Password. Rappelons-le, ce dernier n'est pas accessible à la saisie, pour des raisons de sécurité.
Avant de nous concentrer sur la fonction permettant de valider l'authentification, nous devons appeler la
fonction generation au clic sur le
bouton Generer. En cas de saisie erronée, l'internaute pourra réinitialiser le formulaire pour recommencer.
- Revenir dans l'éditeur de code de la page Html,
- Ajouter l'attribut permettant d'appeler la fonction generation, au clic sur le bouton Generer, situé à la ligne 75 pour un éditeur Notepad :
<input type="text" id="identifiant" maxlength="10" value="Votre identifiant" onClick="init_saisie('1')" onMouseOut="init_saisie('2')"/>
<input type="password" id="motPasse" maxlength="6" value="" readOnly />
<input type="button" class="bouton" value="Valider" />
<input type="button" class="bouton" value="Generer" onClick="generation()"/><br />
<span style="font-size:14px; font-weight:normal;">Paire à reproduire : <strong>bonbache|622551</strong></span>
</div>
- Enregistrer les modifications et basculer sur le navigateur Internet,
- Rafraîchir la page Web avec la touche F5 du clavier,
Dans un premier temps vous constatez que tous les boutons sont réorganisés aléatoirement, comme précédemment.
- Saisir l'identifiant bonbache puis cliquer sur quelques boutons pour inscrire un mot de passe,
- Cliquer alors sur le bouton Generer,
En même temps que les boutons sont replacés, toujours aléatoirement entre les cases 0 et 15, les zones de saisie sont effectivement réinitialisées. Et si vous cliquez de nouveau sur les boutons, vous notez que l'inscription du mot est toujours fonctionnelle.
Le code complet ayant permis le placement aléatoire des boutons pour une identification sécurisée, est le suivant :
function generation()
{
var nb_alea;
var test = true; var chaine = "";
purger();
for (var i=0;i<10;i++)
{
while (test==true)
{
nb_alea = Math.floor(Math.random()*16);
if(chaine.indexOf("-" + nb_alea + "-")>-1)
nb_alea = Math.floor(Math.random()*16);
else
{
document.getElementById('case' + nb_alea).innerHTML = "<input type='button' class='btn' value='" + i + "' onClick='document.getElementById(\"motPasse\").value += " + i +"' />";
chaine += "-" + nb_alea + "-";
test=false;
}
}
test=true;
}
}
function purger()
{
for (var i=0;i<16;i++)
{
document.getElementById('case' + i).innerHTML = "";
}
document.getElementById('identifiant').value = "Votre identifiant";
document.getElementById('motPasse').value = "";
}
Valider l'authentification sécurisée
La paire de connexion utilisée par l'internaute pour s'identifier doit désormais être comparée avec les données d'identification fournies par le script externe. Ce code doit se déclencher au clic sur le
bouton Valider. Nous devons donc créer cette fonction et l'appeler.
- Revenir dans l'éditeur de code de la page Html,
- Après la fonction purger, créer la fonction validation, comme suit :
function validation()
{
}
Nous avons besoin de variables pour récupérer les informations de connexion et les stocker indépendamment.
- Dans les bornes de la fonction, ajouter les déclarations suivantes :
var combinaison = id_mp().split('|');
var ident = combinaison[0];
var mp = combinaison[1];
Tout d'abord, la
méthode split appliquée sur une chaîne de caractères, permet de découper cette dernière sur l'occurrence qui lui est passée en paramètre. Dans la
fonction du script externe, l'identifiant et le mot de passe sont en effet séparés par une barre verticale(|). Nous l'avions d'ailleurs exploitée dans la
formation Javascript pour créer un album photo et dissocier toutes les images mémorisées. Le résultat de cette méthode a pour effet de transformer la variable qui est affectée, en
tableau de variables. Ce dernier propose désormais autant de lignes que d'informations indépendantes sont rangées. Dans notre cas, il s'agit seulement de deux éléments : l'identifiant et le mot de passe. Le premier s'obtient en pointant sur la première ligne, repérée par l'indice 0 (combinaison[0]). Le second, fort logiquement, s'obtient en pointant sur l'indice 1.
Désormais, les informations d'identification sont clairement mémorisées et peuvent donc être comparées avec les données entrées par l'internaute. Pour que l'authentification soit un succès nous devons vérifier en même temps que les identifiants coïncident et que les mots de passe sont identiques. C'est encore une
instruction conditionnelle Javascript qui va permettre de vérifier ce double critère exclusif.
- A la suite du code de la fonction validation, ajouter les instructions suivantes :
if(document.getElementById('identifiant').value.toLowerCase() == ident.toLowerCase() && document.getElementById('motPasse').value == mp)
document.getElementById('apercu').innerText = "Vous êtes désormais connecté";
else
document.getElementById('apercu').innerText = "L'authentification a échoué";
C'est l'
opérateur && dans une instruction conditionnelle Javascript, qui permet d'imposer la double vérification. Si l'un des deux critères n'est pas satisfait, la condition globale est considérée comme non remplie. La
propriété value des
contrôles Input Html permet d'accéder respectivement au contenu des éléments d'
identifiant identificant et motPasse. La
méthode Javascript toLowerCase permet de convertir les informations en minuscules pour qu'il n'y ait pas de différence de casse dans la comparaison.
Dans le cas où les deux conditions sont vérifiées, la
propriété innerText du
contrôle Div, permet d'inscrire un message de
succès à l'authentification, dans le
calque apercu situé en bas de la page Html. Dans le cas contraire, c'est un message d'échec qui est inscrit.
Nous devons maintenant appeler cette fonction au clic sur le
bouton Valider.
- Ajouter la gestion de l'événement du clic dans le code Html du bouton Valider, en ligne 74 pour un éditeur Notepad, comme suit :
<input type="text" id="identifiant" maxlength="10" value="Votre identifiant" onClick="init_saisie('1')" onMouseOut="init_saisie('2')" />
<input type="password" id="motPasse" maxlength="6" value="" readOnly />
<input type="button" class="bouton" value="Valider" onClick="validation()"/>
<input type="button" class="bouton" value="Generer" onClick="generation()" /><br />
<span style="font-size:14px;font-weight:normal;">Paire à reproduire : <strong>bonbache|622551</strong></span>
</div>
- Enregistrer les modifications et basculer sur le navigateur Internet,
- Rafraîchir la page avec la touche F5 du clavier,
- Saisir un identifiant et cliquer sur les boutons de manière à inscrire un mot de passe erroné,
- Cliquer sur le bouton valider,
Comme vous le remarquez, le message d'échec apparaît instantanément dans le calque inférieur.
- Cliquer sur le bouton Générer pour replacer aléatoirement les boutons de code,
- Saisir le bon identifiant : bonbache,
- Puis inscrire le vrai mot de passe en cliquant sur les boutons dédiés : 622551,
- Cliquer sur le bouton valider,
Cette fois, l'
identification est un succès comme en atteste le message du calque inférieur. Aucun des chiffres du mot de passe n'a été saisi au clavier. De plus, leur inscription par clic se fait depuis des emplacements perpétuellement renouvelés, grâce à ce
positionnement aléatoire. La
sécurisation de la connexion est donc un succès puisqu'aucun logiciel malveillant de type keylogger, n'est en mesure d'enregistrer les frappes du mot de passe.
Le code complet de la fonction validation est le suivant :
function validation()
{
var combinaison = id_mp().split('|');
var ident = combinaison[0];
var mp = combinaison[1];
if(document.getElementById('identifiant').value.toLowerCase() == ident.toLowerCase() && document.getElementById('motPasse').value == mp)
document.getElementById('apercu').innerText = "Vous êtes désormais connecté";
else
document.getElementById('apercu').innerText = "L'authentification a échoué";
}
Encore une fois, la fin de l'application doit consister en une transmission des informations du
code Javascript à un
code serveur Php. C'est lui qui doit se charger d'interroger la base de données afin de valider la correspondance de ces informations confidentielles. Néanmoins, nous avons ici parfaitement réussi Ã
sécuriser l'application d'authentification, par le
code client Javascript, afin d'empêcher l'enregistrement des caractères saisis.