Authentification d'un espace membre avec PHP

m@

Cet article est un condensé des bonnes pratiques en matière d'authentification sur Internet. Il a été essentiellement élaboré à partir des nombreux threads sur le sujet du forum PHP de developpez.com

- Titre : Authentification d'un espace membre avec PHP

- Auteur : m@

- Parution : 30 juin 2004

- Mise à jour : 11 décembre 2019

- Licence : 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 ® 2004 m@. 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.

Sommaire

- I. Conception des formulaires

- II. Stockage des mots de passe sur le serveur

- II-A. L'algorithme md5

- II-B. Technique du grain de sel

- III. Transmissions sécurisées (HTTPS)

- IV. Permanence des informations (cookies, sessions)

- V. Protection contre les attaques bruteforce

- VI. Erreurs humaines

- VII. Considérations diverses

- VIII. Remerciements

I - Conception des formulaires

L'authentification commence au moment où vous demandez son mot de passe à votre visiteur, voilà quelques remarques.

- Les champs de type password offrent une protection contre les yeux baladeurs par l'affichage d'astérisques à la place des caractères tapés, et leur valeur n'est pas mise en cache par le navigateur.

- Une autre possibilité est la demande du mot de passe par HTTP. Le mot de passe est alors demandé directement dans une boîte de dialogue, et non dans une page HTML.
Remarque : une fois le mot de passe saisi, le navigateur retransmettra automatiquement login et mot 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);

II - Stockage des mots de passe sur le serveur

- 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 chiffrés.

II-A - L'algorithme md5

- Md5 (message digest 5) est un algorithme transformant vos mots de passe en une chaîne indéchiffrable appelée hash.

- Chiffrer deux fois le même mot de passe avec md5 donnera deux fois le même hash.

- On chiffre donc le mot de passe à l'enregistrement, puis à chaque login, on chiffre 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/.

- D'autres algorithmes peuvent être utilisés pour remplacer md5. Attention par contre à l'utilisation de base64 qui n'est pas un algorithme de chiffrage et n'offre aucune sécurité.

Obtenir le hash md5 d'un mot de passe en PHP

$motDePasseCryptÃ© = md5($motDePasse);

II-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 chiffrait tous les mots de passe probables avec md5 (ou au moins un très grand nombre) on pourrait à 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 chiffrer, 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à une 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.

III - Transmissions sécurisées (HTTPS)

- 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 chiffré 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 SSL.

- 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.

IV - Permanence des informations (cookies, sessions)

- 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 à votre insu.

- 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écédente est courant, mais 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 : https://php.developpez.com/faq/?page=sessions.

- 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 sessions par un très bon tutoriel : https://julp.developpez.com/php/les-sessions/.

V - Protection contre les attaques bruteforce

- Une attaque bruteforce consiste à essayer un maximum de mots de passe possibles en espérant tomber sur le bon.

- Bloquer un compte après trois é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 passe complexes, que nous détaillerons sous peu.

Récupérer l'IP d'un visiteur

$ip = $_SERVER["REMOTE_ADDR"];

Temporiser

//recupere($temps);
sleep($temps);
$temps = $temps * 2;
//stocke($temps);

VI - Erreurs humaines

- 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 Postit abandonné sur le bureau.

- Enfin vous pouvez tester la robustesse d'un mot de passe par crack, qui est accessible de façon expérimentale 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.

VII - Considérations diverses

- 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 le 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. Cela ne veut pas dire que ces infos sont inintéressantes pour vos stats, mais qu'elles sont globalement inutiles pour authentifier vos visiteurs. Pour citer Saint-Exupéry :
« On atteint la perfection, non pas lorsqu'il n'y a plus rien à ajouter, mais lorsqu'il n'y a plus rien à retirer. »

- Enfin voilà quelques liens sur le sujet, fournis par Sub0 (Sub0 a écrit un espace membre, auquel participe la communauté de developpez.com sur ce forum : https://www.developpez.net/forums/viewtopic.php?t=220791):

- https://bob.developpez.com/phpauth/

- https://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

VIII - Remerciements

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.
Et tout particulièrement à Bob, Jérôme, Mathix, Sub0 et Swoog pour leurs encouragements, conseils et relectures.

(c) Matthieu Pometan al m@ pour developpez.com - juillet 2004
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 !!