Authentification d'un espace membre
Cet article se veut
๊tre un condens้ des bonnes pratiques en mati่re d'authentification sur internet.
Il a ้t้ essentiellement
้labor้ เ partir des nombreuses threads sur le sujet du forum PHP.
1.
Conception des fomulaires
2. Stockage des mots de passe sur le serveur
3. Transmissions sécurisées (HTTPS)
4. Permanence des informations (cookies, sessions)
5. Protection contre les attaques bruteforce
6. Erreurs
humaines
7. Considérations diverses
L'authentification commence au moment où vous demandez son mot de passe à votre visiteur, voilà quelques remarques :
Le champ <input type="password" name="leSuperMotDePasse" /> offre une protection contre les yeux baladeurs par l'affichage d'ast้risques เ la place des caract่res tap้s. Rien d'autre. Le mot de passe reste donc accessible pour des langages comme Javascript, VBScript... Par exemple, si un visiteur arrive sur votre site par un lien du type : onClick="window.open('www.monSiteAProteger.com/laPageDeLogin.htm', 'popup');"
le site เ l'origine de la popup peut acc้der au mot de passe par quelquechose comme popup.nomDuForm.leSuperMotDePasse.value
D้mo :
Au niveau de la demande du mot de passe, mieux vaut donc passer par l'authentification HTTP. En effet, le mot de passe n'est pas alors demand้ dans une page HTML mais dans une fen๊tre du navigateur.
Remarque : une fois saisis, le navigateur retransmettra automatiquement logins et mots de passe durant toute la session.
Demander un mot de passe via HTTP en PHP :if (! $PHP_AUTH_USER || ! $PHP_AUTH_PW)
{
header('status: 401 Unauthorized');
header('HTTP/1.0 401 Uauthorized');
header("WWW-authenticate: Basic realm=\"test de l'authentification HTTP\"");
}
echo ($PHP_AUTH_USER, ' ', $PHP_AUTH_PW);
Pour pouvoir être comparés avec ceux rentrés par les utilisateurs, vos mots de passe doivent être enregistrés sur votre serveur dans une base de données ou un fichier.
Pour contrer un piratage du serveur, ils doivent être cryptés.
a)L'algorithme md5
Md5 est un algorithme transformant vos mots de passe en une chaîne indécryptable appelée hash.
Crypter deux fois le même mot de passe avec md5 donnera deux fois le même hash.
On crypte donc le mot de passe à l'enregistrement, puis à chaque login, on crypte le mot de passe transmis, et on le compare à la version stockée sur le serveur.
Pour un exemple de md5, allez voir : http://pajhome.org.uk/crypt/md5/
Obtenir le hash md5 d'un mot de passe en PHP :$motDePasseCrypté = md5($motDePasse);
D'autres algorithmes peuvent être utilisés pour remplacer md5. Attention par contre à l'utilisation de base64 qui n'est pas un algorithme de cryptage et n'offre aucune sécurité
b)Technique du grain de sel
Cette technique est utilisée par UNIX et permet de se protéger en cas de vol du hash md5
Comme une même chaîne donne toujours le même hash avec md5, si on cryptait tous les mots de passe probables avec md5 (ou au moins un très grand nombre) on pourrrait à partir d'un hash retrouver le mot de passe en clair.
La constitution d'un tel dictionnaire prend du temps et doit être faite à l'avance, toutefois elle est envisageable.
La parade se fait par l'introduction d'un grain de sel qui va "déformer" le hash.
Ce grain de sel est en fait un très grand nombre que l'on concatène au mot de passe avant de le crypter, mais un exemple éclairera tout :$motDePasse = "toto";
$hash = md5($motDePasse);
$hash contient alors f71dbe52628a3f83a77ab494817525c6 qui est le hash de toto.
Si l'on avait un dictionnaire avec tous les hashs possibles, on pourrait alors associer f71dbe52628a3f83a77ab494817525c6 à toto et donc avoir le mot de passe.
Maintenant, voilà l'application du grain de sel :
$motDePasse = "toto";
$grainDeSel = nombreAleatoire();
$hash = md5($motDePasse.$grainDeSel);
$grainDeSel n'est pas secret, est propre à chaque utilisateur et est stocké en clair dans la base de données.
Pour retrouver $motDePasse à partir de $hash, il faudrait donc maintenant un dictionnaire de tous les mots de passe possibles, concaténés avec $grainDeSel.
Nous avons déjà dit que la réalisation d'un dictionnaire doit être faite à l'avance, c'est à dire à un moment où on ne connaît pas $grainDeSel. Il faudrait donc réaliser un dictionnaire pour chaque grain de sel possible, ce qui est inenvisageable
HTTPS est le nom donné au protocole HTTP (pour mémoire, le protocole HTTP est le "langage" permettant la transmission des informations sur le web) quand il est crypté avec SSL.
HTTPS permet l'authentification de votre serveur
le secret des informations transmises, dans les deux sens
l'intégrité de ces informations. En simplifiant, on peut comparer HTTPS à un tunnel inviolable reliant deux ordinateurs. On a la garantie que les infos mises à un des bouts du tunnel arrivent à l'autre bout, sans avoir été observées ou altérées. De plus, il est possible d'acheter un certificat SSL, indiquant de façon fiable que tel ordinateur est bien la propriété de telle société et non d'un pirate.
L'achat de certificat n'est pas nécessaire pour authentifier vos utilisateurs, mais pour empêcher un pirate de se faire passer pour vous.
Pour plus d'informations sur les certificats, allez voir http://www.reacteur.com/search/14?kw=Certificat%20SSL
Sans certificat l'utilisation de HTTPS peut se faire de façon gratuite, et nécessite alors sous Apache l'installation du module mod_ssl.
OpenSA ( http://www.opensa.org/) propose un package d'installation d'Apache avec mod_ssl, pour windows.
Une fois protégé par HTTPS, on accède alors à votre site par https://www.monsite.com
Cela n'entraîne aucune modification de votre code.
Vous pouvez éprouver le besoin de conserver des informations d'une page à une autre. Ces informations, peuvent être sensibles et doivent être protégées.
Les cookies sont des petits fichiers stockés sur les ordinateurs de vos visiteurs. Vos visiteurs peuvent y avoir accès et les modifier.
Il n'est donc pas raisonnable de se baser sur les cookies pour savoir par exemple si un utilisateur est bien authentifié ou pas.
De même, authentifier vos visiteurs par un cookie stocké lors de leur visite précedente est risqué. Le vol de ce cookie permettrait une connexion sans mot de passe.
La même remarque s'applique aux variables transmises par URL ou par input hidden.
Les sessions de PHP vous permettent de définir des variables communes à plusieurs scripts, dans un contexte plus sécurisé, le vol de session reste toutefois encore possible.
Seul un identifiant est alors stocké chez l'utilisateur.
La sécurité des sessions est présentée ici : http://www.nexen.net/docs/php/annotee/session.security.php
La FAQ est ici : http://cyberzoide.developpez.com/php4/faqsession/
Remarquez en particulier la nécessité d'utiliser session.use_only_cookies et de configurer le serveur pour que les sessions soient stockées dans un répertoire protégé.
Vous pouvez tenter de renforcer les sessions par le stockage de l'IP et du port de votre visiteur. Toutefois ces informations peuvent évoluer avec le temps.
Il peut également être intéressant de donner une durée de vie à vos sessions.
Enfin pour éviter le vol de session, appelez session_regenerate_id() (PHP >= 4.3.2) à chaque chargement de page pour modifier l'ID.
Si tout cela vous semble obscur, prenez le temps de vous familiariser avec les session par un très bon tutoriel : http://julp.developpez.com/php/les-sessions/
Une attaque bruteforce consiste à essayer un maximum de mots de passe possible en espérant tomber sur le bon.
Bloquer un compte après 3 échecs est une mauvaise solution. En effet, il devient alors incroyablement simple de paralyser le serveur, en bloquant tous les comptes utilisateurs.
Il est plus pertinent de bloquer l'IP ayant tenté de se connecter.
On peut également temporiser un temps de plus en plus grand avant d'autoriser un nouvel essai.
La protection contre le bruteforcing passe aussi par le choix de mots de passes complexes, que nous détaillerons sous peu.
Récupérer l'IP d'un visiteur :$_SERVER["REMOTE_ADDR"];
Temporiser :
//recupere($temps);
sleep($temps);
$temps = $temps * 2;
//stocke($temps);
Ici encore, la plus grande faille de votre système reste encore vos utilisateurs.
Vous pouvez choisir d'obliger vos utilisateurs à changer de mot de passe à intervalle régulier, en stockant la date de changement de mot de passe dans une base de données.
Soyez toutefois vigilant, si ce processus est trop fréquent, vos utilisateurs risquent de ne plus prendre la peine de choisir des mots de passe robustes.
Vous pouvez également imposer à vos utilisateurs des mots de passe aléatoires, en prenant le risque qu'ils le notent sur un post-it abandonné sur le bureau.
Enfin vous pouvez tester la robustesse d'un mot de passe par crack, qui est accessible de façon expériementale en PHP.
Pour plus d'informations sur crack, allez voir la documentation PHP ou http://www.users.dircon.co.uk/~crypto/
Tester si un mot de passe est fiable avec crack :$dico = crack_opendict('/le/chemin/du/dictionnaire');
if (! crack_check($dico, $motDePasse))
{
echo "Votre mot de passe n'est pas suffisamment robuste";
}
crack_closedict($dico);
En dehors des mots de passe, expliquez également à vos visiteurs l'importance de se déconnecter à la fin de leur visite.
Si vos utilisateurs ne se déconnectent pas, les variables de session ne seront détruites que quand toutes les fenêtres de leur navigateur seront fermées.
Le risque est par exemple particulièrement important dans les cybercafés.
Je terminerai cet article par quelques réflexions personnelles sur la nécessité et la "philosophie" de l'authentification. Ce qui suit reste mon point de vue, et il est en tant que tel discutable... mon mail est à la fin !
Nécessaire ? Après avoir lu ce texte, la première question à vous poser est : est-ce nécessaire ? si vous développez un site perso avec un forum, il est probable que la seule conséquence d'un hacking soit un post avec le login de quelqu'un d'autre. Bien que cela puisse donner lieu à des quiproquos regrettables ("Comment ça tu veux qu'on divorce ??") la portée reste limitée. Dans ce cas, soyez assez honnête avec vous même pour apprécier à sa juste valeur votre besoin de protection, et ne pas céder à la tentation d'alourdir votre code pour le transformer en forteresse.
Suffisant ? Après, peut-être êtes-vous en train de programmer l'intranet de la CIA (si c'est la cas, écrivez moi quand même, ça me ferait plaisir !). Soyez là aussi lucide : les quelques conseils donnés ici ne rendront jamais aucun site inviolable. Prenez conseil auprès d'un expert, ou sous traitez la réalisation de votre authentification. Enfin réalisez tout votre code en gardant à l'esprit l'éventualité d'un piratage réussi, et estimez ses conséquences.
Security Through Obscurity : Le STO désigne toutes les pratiques utilisées pour dissimuler le code, rendre les informations moins compréhensibles, etc. Je range avec toutes les bidouilles comme la réalisation d'un algorithme de cryptage maison, etc. N'oubliez pas que ce qui embrouille un pirate vous embrouillera aussi pour patcher une faille. Plutôt que de bidouiller, utilisez des moyens conventionnels, qui sont étudiés par de nombreux experts de la sécurité, et qui seront donc infiniment plus sûrs que vos idées maison. Ainsi, si par exemple vous ne pouvez pas disposer d'un serveur HTTPS, ne tentez pas de le réinventer. Mieux vaut encore garder un code clair et logique, même si les infos voyagent en clair.
Simplicité : Dans la continuité du paragraphe précédent, restez simple : ne surchargez pas votre code de paramètres comme la version du navigateur pour tenter de découvrir un hypothétique hacking. Pour citer Saint-Exupéry :"On atteint la perfection, non pas lorsqu'il n'y a plus rien à ajouter, mais lorqu'il n'y a plus rien à retirer"
Enfin voilà quelques liens sur le sujet, fournis pas Sub0:
http://bob.developpez.com/phpauth/
http://thierrylhomme.developpez.com/php/php_secure/
http://www.commentcamarche.net/crypto/ssl.php3
http://www.commentcamarche.net/crypto/ssh.php3
http://www.hsc.fr/ressources/presentations/ces-xss/ces-xss.pdf
http://www.urec.cnrs.fr/securite/outils/ssh/documentation-ssh.pdf
http://securit.free.fr/ressources/ssl_v3.pdf
http://www.salemioche.com/doc/ssl4.php
http://www.rcmp.ca/scams/ccprev_f.htm
http://www.certa.ssi.gouv.fr/site/CERTA-2003-AVI-057/index.html.2.html
Merci à tous les habitués de developpez.com pour leurs participations
aux nombreux débats qui ont agité le forum PHP et nourri cet article
!
Matthieu Pometan al m@
<matthieu@grimpentete.org>
<-n'hésitez pas à balancer toutes vos critiques, suggestions,
ou même remerciements (qui sait) sur ce mail, c'est fait POUR !!