dimanche 15 juin 2008

Zend_Auth et le cookie masqué

Je vais encore vous parler de cookies, mais cette fois-ci à la sauce Zend_Auth.

Je vous ai présenté dans un précédent article une classe permettant de gérer des cookies sécurisés. Maintenant nous allons voir comment l'utiliser dans un cas très courant : l'authentification avec Zend_Auth.

Rappelons les grandes lignes de Zend_Auth :

Si comme moi vous n'utilisez les sessions que pour stocker l'identité des utilisateurs authentifiés (leur identifiant, un simple nombre entier en général), vous allez peut être trouver que c'est du gachi. Les sessions c'est lourd et ennuyeux à gérer quand l'application en question tourne sur une ferme de serveurs web (qui font meuh meuh en core et en core).

Bref, ne serait-il pas tentant de déléguer cette tâche au client ? Qu'il présente lui même son identité ? C'est risqué vous allez dire... et vous avez raison !
On peut déjà imaginer les pires scénarios :

Serveur> Bien le bonjour ! A qui ai-je l'honneur ?
Client (de type malicieux)> Je suis l'administrateur du site ! Regarde j'ai... ma bonne parole pour te le prouver !
Serveur> Salut chef je t'avais pas reconnu. Voici les clefs de ton royaume.

Techniquement, ca reviendrait a stocker l'user_id dans un cookie et de faire complètement confiance à ce cookie.

En général ce genre de scénarios est très peu apprécié par le public (en particulier celui de votre site). Donc on va tenter d'utiliser quelques ruses cryptographiques pour confier à l'utilisateur le soin de présenter son identité, sans qu'il puisse la modifier : on va la stocker dans un cookie sécurisé grâce à la classe BigOrNot_CookieManager.

J'ai donc écrit une classe qui implémente l'interface Zend_Auth_Storage_Interface pour stocker l'identité des utilisateurs dans un cookie sécurisé.

Vous pouvez la télécharger ici (l'archive contient également la classe BigOrNot_CookieManager).

Voici comment l'utiliser :

$cookieManager = new BigOrNot_CookieManager('SECRET_KEY');
$authStorage = new BigOrNot_Auth_Storage_Cookie($cookieManager);
$auth = Zend_Auth::getInstance();
$auth->setStorage($authStorage);

[...]

Par defaut, le cookie s'appelle "auth" et les paramètres par défaut sont envoyes a setcookie().

Si vous souhaitez modifier ces paramètres, il est possible d'envoyer au constructeur de la classe BigOrNot_Auth_Storage_Cookie un deuxième paramètre : un tableau (ou un objet Zend_Config) de configuration.

Les paramètres de configuration supportés sont : cookieName, cookieExpire, cookiePath, cookieDomain, cookieSecure, cookieHttpOnly. (Les noms sont assez explicites, voir la doc de setcookie() si vous avez des doutes).

Exemple d'utilisation avec configuration :

$cookieManager = new BigOrNot_CookieManager('SECRET_KEY');

$storageConfig = array(
    'cookieName' => 'BigOrNauth',
    'cookieExpire' => (time() + 3600),
    'cookiePath' => '/',
    'cookieDomain' => 'bigornot-fr.blogspot.com'
);

$authStorage = new BigOrNot_Auth_Storage_Cookie($cookieManager, $storageConfig);
$auth = Zend_Auth::getInstance();
$auth->setStorage($authStorage);

L'identité est stockée "serialisée" donc vous pouvez y stocker toute valeur serialisable. Evitez tout de même les gros objets, les cookies trop gros sont vite écoeurants. N'oubliez pas qu'ils sont transmis à chaque requête.

L'identité est également stockée chiffrée, donc vous ne donnez aucune information confidentielle à l'utilisateur en utilisant cette technique.

Pour information :
Comme nous l'avons vu dans le précédent article, pour la methode BigOrNot_CookieManager::setCookie(), il est necessaire d'envoyer en paramètre un nom d'utilisateur (ou n'importe quel identifiant unique).
Dans la classe BigOrNot_Auth_Storage_Cookie, j'envoie un hash md5 de l'identite serialisee.

2 commentaires:

Mike Dename a dit…

merci pour cette série d'articles très intéressants.
Une petite question : pourquoi ne pas avoir utilisé Zend_http_cookie ? Est ce que cette fonctionnalité n'était pas encore dispo à l'écriture de l'article ou c'est un choix délibéré ?
Si c'est la 2ème option j'aimerai bien avoir une petite explication :)
Merci d'avance

Mat a dit…

Merci Mike ! Pour te répondre, à l'époque, Zend_Http_Cookie existait bel et bien. J'avais regardé du coté de ce composant et j'en avais déduit qu'il était fait pour être utilisé avec Zend_Http_Client.

C'est pour cela que j'ai utilisé la fonction native setcookie() ainsi que $_COOKIE[].

Si tu as une suggestion pour réécrire ce code autrement, n'hésite pas je suis preneur :)