samedi 11 juin 2011

Authentification HTTP, Apache Shiro !

Introduction

L'authentification est un procédé qui consiste à identifier une entité à partir d'éléments constituant ses caractéristiques – en général le couple login/mot de passe. L'entité à authentifier peut être une personne physique, un ordinateur ou un programme informatique. La finalité de l'authentification est de contrôler l'accès à des ressources sécurisées.

On parle d'Authentification Http quand l'authentification s'effectue auprès d'un serveur web. Pour une application web l'authentification présente un enjeu majeur, dans la mesure où elle est accessible de partout et de tout le monde et traitent des données privées – souvent très sensibles - d'une entreprise. C'est dans le [RFC 2617] du protocole Http qu'est précisée la spécification des Framework d'authentification Http. Le principe est le suivant : les ressources sécurisées ne sont accessibles que par un groupe d'utilisateurs capables de satisfaire une demande d'authentification venant du serveur.

1. Quand le serveur reçoit - d'un utilisateur non authentifié - une requête Http sur une ressource sécurisée il répond avec le Status 401 (Unauthorized : non autorisé) et invite le client à s'authentifier en positionnant le Header de la réponse à WWW-Authenticate (1 et 2 figure 1). Sur un navigateur cette demande se matérialise par l'affichage d'une boite de dialogue mais c'est souvent transparent dans la plus part des application.

2. Le client réitère la requête en fixant ses identifiants dans le Header [champs Authorization] (3 et 4 figure 1). Si l'authentification réussi l'accès à la ressource est donnée (Status 200 : OK), à l'inverse le serveur répond avec le Status 401 pour informer le client de l'échec de l'authentification.


figure 1

Les deux principaux mécanismes d'authentification Http sont le Basic et le Digest.

Authentification Basic

C'est le moins sécurisé, le login et le password sont connus du client et du serveur.
Entête d'une demande de d'authentification :


HTTP/1.1 401 Unauthorized,
WWW-Authenticate: Basic,
realm="My Server",
Content-Length: 0


Et la réponse du client :


GET /protectedresources/ HTTP/1.1,
Host: http://www.protectedwebsite.com/rest,
Authorization: Basic XXXXXXX =


XXXXXXX étant l'encodage en base64 de la concaténation login:password (L'encodage ne crypte pas, il permet seulement de formater les données afin éviter d'éventuels conflits avec des mots réservés). Après la réception de la requête réitérée du client le serveur décode et fait la comparaison avec les identifiants qu'il a en base. L'authentification Basic n'est pas sécurisée dans la mesure où les données ne sont pas cryptées. En général elle est couplée avec un protocole sécurisé comme HTTPS ou SSL.

Authentification Digest

Dans l'authentification digest les données échangées sont cryptées avec l'algorithme de cryptage MD5 qui est irréversible (on ne peut pas déduire les paramètres d'entrée à partir du résultat) . Toutefois le cryptage seul ne met pas le système à l'abri d'un « Reply attack »; quand les données cryptées sont interceptées elles pourront être utilisées pour accéder au système. Pour ajouter plus de sécurité toutes les échanges entre le client et le serveur sont signées avec le champs nonce (number used once). La signature est connue du Serveur et du Client et a une durée de vie limitée.

Entête Http du serveur :


HTTP/1.1 401 Unauthorized,
WWW-Authenticate: Digest,
realm="My Server",
nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",
...


Entête Http du client :


Authorization: Digest,
username = "yakhya.dabo",
realm = "My Server",
nonce = "dcd98b7102dd2f0e8b11d0f600bfb0c093",
uri = <requested-uri>,
response = "xxxxxxxxxxx",


avec
response = MD5 (A1 + ":" + nonce + ":" + A2)
A1 = MD5 (username + ":" + realm + ":" + password)
A2 = MD5 (httpMethod + ":" + uri)

A la réception de la réponse le serveur fait la comparaison en faisant le même calcul MD5 avec les mêmes paramètres (login, password, nonce, …) puisqu'il les dans sa base de données.
MD5(MD5(login:realm:password):nonce:MD5(httpMethod:uri))

Framework d'authentification HTTP

En Java beaucoup de frameworks Open Source d'authentification Http sont actuellement disponibles. SpringSecurity - sans doute le plus populaires – est celui qui sort la tête du lot mais en plus de sa forte adhérence avec Spring (trop de dépendances) et de la complexité de son implémentation liée au nombre de fichiers de configuration XML) il présente deux insuffisances majeures qui rendent sont utilisation dans le projet impossible :

    • L'absence d'intégration de Guice.
    • Non prise en charge par Google Apps Engine.

Apache Shiro

Apache Shiro (anciennement connu sous le nom de JSecurity) qui va au delà de l'authentification Http se fait de plus en plus de la place dans le domaine de la sécurité. Même s'il souffre encore d'une documentation de faible qualité sa mise en œuvre est très simple et concepts manipulés facilement compréhensibles. Il offre des services d'authentification, de gestion des droits, de cryptographie et de gestion de sessions utilisateur et peut être utilité en dehors d'un conteneur web. Il y actuellement beaucoup d'autres frameworks qui s'intègrent facilement avec Shiro (Spring, Grails, Apache Camel et Vaadin).

Les concepts qui sont manipulés par Shiro :

    • Subject : C'est l'objet qui est présentement en interaction avec l'application, il peut s'agir d'un être humain, d'un processus, d'une tâche de fond, ... Le terme Subject est volontairement choisi à la place de User pour éviter la confusion avec User au sens humain.
    • Credentials : Ce sont des données secrètes qui permettent d'authentifier un Subject. Il peut s'agir de mots de passe, de données biométriques, de certificats, …

    • Principals : L'ensemble des attributs du Subject. Le nom, le prénom, le login, …
    • Realm : Il fonctionne comme un DAO en encapsulant l'accès aux sources de données où sont stockées les Credentials. Pour une même application plusieurs Realm peuvent être configurés, un dédié à la connexion avec le serveur LDAP, un avec une base de données, un autre avec un autre serveur LDAP, …