Il est très courant de devoir protéger une partie d'un site, que ce soit une section d'administration ou simplement un espace privé. Plusieurs solutions d'authentification par login / mot de passe s'offrent à nous.
Le principe d'authentification par formulaire est simple :

Lors de la navigation sur la partie privée, il faudra déterminer si l'utilisateur s'est déjà logué. Les techniques les plus courantes sont l'utilisation des cookies et sessions. Petit rappel sur ces derniers :
Dans notre cas, il est préférable d'identifier l'utilisateur grâce aux sessions en terme de sécurité (seul l'id de session transite sur le réseau) et de pratique (stockage de variables utilisées de façon récurrente).
L'avantage de l'authentification par formulaire réside dans sa facilité d'administration : la liste d'utilisateurs autorisés peut être stockée en base de donnée, un annuaire LDAP ou encore un fichier plat. Cependant, il est important de noter qu'elle ne permet pas de protéger les fichiers html, images et documents divers accessibles directement par l'url.
Les risques d'utiliser les sessions à ce stade se situent à deux niveaux :
Ces problèmes peuvent être résolu par l'utilisation du protocole HTTPS, expliqué dans le chapitre suivant.
Concrètement, un htaccess est un fichier de configuration du serveur http. Il permet (entre autre) de limiter les droits d'accès à un répertoire du site. Ceci est utile pour réserver une zone d'administration ou offrir un espace membre.
Il faut savoir que les htaccess peuvent s'écrire directement dans le fichier de configuration d'Apache. Il suffit pour cela d'encadrer les directives dans un <Directory> avec le chemin du répertoire à protéger ou un <Location> avec l'URL.
<Directory /usr/www/administrateur> ... </Directory>
Ou :
<Location /> ... </Location>
Il existe deux méthodes d'authentification décrite dans la RFC 2617 du protocole http : basic et digest.
Le mécanisme basic est communément employé du fait de se compatibilité et simplicité de mise en oeuvre.
HTTP/1.1 401 Authorization Required WWW-Authenticate: Basic realm="private Access"

Une fois saisies, les informations sont renvoyées au serveur. Le navigateur réitère la précédente requête en y intégrant l'entête d'autorisation. Le nom d'utilisateur et le mot de passe sont alors concaténés (séparés par « : ») et encodé en base64. Par exemple, pour un login / mot de passe user:password, la requête est la suivante :
GET / HTTP/1.0 Authorization: Basic dXNlcjpwYXNzd29yZA==
Les accréditations sont ensuite mises en cache, évitant de les ressaisir à chaque requête.
Cette méthode est donc très sensible à toute écoute de trafic puisque les informations ne sont pas chiffrées et renvoyées dans chaque entête. Tout comme l'authentification par formulaire, une solution de transport par SSL est fortement envisageable.
AuthType Basic AuthName "private access" AuthUserFile /etc/httpd/conf/htpasswd Require valid-user
Le fichier des utilisateurs peut être généré à l'aide de l'utilitaire htpasswd.
Contrairement au mode basic, cette méthode met en oeuvre un service de confidentialité pour les accréditations, introduisant un mécanisme contre le rejeu et protégeant le client contre un serveur malveillant.
Le mécanisme est connu sous le nom de « challenge/response » : le serveur envoie un challenge au client, celui-ci répond par une valeur dérivée de ce challenge et d'un secret qu'il partage avec le serveur. Le serveur s'assure que le client possède effectivement le secret en calculant à son tour la réponse.
HTTP/1.1 401 Authorization Required WWW-Authenticate: Digest realm="private Access", nonce="vR54Tk==a965d986fa716e4d4592943b5762c73958f0328C", algorithm=MD5, domain="/", qop="auth"
Pour chaque requête, le client devra calculer sa réponse à partir de ces paramètres. Le challenge n'étant pas renouvelé à chaque fois, cela limite le non-rejeu.
Il faut savoir que le serveur n'a pas connaissance du mot de passe. Dans le fichier utilisateur, est conservé le login, le realm, et un hachage du « login:realm:password ». On obtient au final une réponse de ce style :
GET / HTTP/1.1 Authorization: Digest username="user", realm="private Access", nonce="vR54Tk==a965d986fa716e4d4592943b5762c73958f0328c", uri="/", algorithm=MD5, response="411d4c35a806746ab353c67ab4e9cf5a", qop=auth, nc=00000001, cnonce="af08d67c532a3a01"
HTTP/1.1 200 OK Authentication-Info: rspauth="1d4d5a9d920fb22197471146c613e767", cnonce="be09d67c532a3a02", nc=00000001, qop=auth
rspauth permet une authentification mutuelle, prouvant que le serveur connais effectivement le mot de passe du client.
Il est important de noter que le non-rejeu se situe au niveau « session http » (durée pendant laquelle le nonce est utilisable) et non au niveau requête http. La durée de vie est définit dans la configuration du module mod_auth_digest grâce au paramètre AuthDigestNonceLifetime. Au-delà de cette durée, le nonce sera renouvelé et le client devra s'authentifier à nouveau. On peut donc s'apercevoir que ce module propose un réel système de confidentialité des accréditations et non un véritable service de non-rejeu.
Outre ses nombreux avantages, le module Digest est aussi connu pour son incompatibilité entre Apache et Internet Explorer et par conséquent entre IIS et tous les navigateurs (sauf MSIE bien entendu). Cette incompatibilité est due à une mauvaise interprétation de la RFC 2616 par Microsoft.
Le problème se situe au niveau du calcul de la réponse. Comme nous avons pu le constater, le client génère sa réponse avec l'URI (entre autre). La RFC définit que la QUERY_STRING (chaîne figurant après « ? ») doit être prise en compte, hors MSIE et IIS ne le font pas. Par conséquent lorsque le serveur vérifie la réponse du client en la recalculant, celle-ci ne correspond pas et le client est rejeté avec une erreur 400 Bad Request.
La solution à ce problème est simplement de ne pas passer les variables en GET mais dans le corps de la requête : en POST.
AuthType Digest AuthName private Access AuthDigestFile /etc/httpd/conf/htpasswd Require valid-user
Le fichier des utilisateurs peut être généré à l'aide de l'utilitaire htdigest.
Attention : en Digest, AuthName permet d'identifier l'utilisateur en plus de son login. Cela peut permettre de regrouper des utilisateurs dans une section. Il doit correspondre avec le realm dans le fichier des utilisateurs.