Mod_headers à la rescousse du jsessionid

Au cours de la migration d’une cinquantaine d’applications web de Websphere vers JBoss 5.1 EAP, nous avons été confrontés à un problème de sécurité mis en évidence par l’infrastructure de pré-production : le firewall bloquait systématiquement toute requête comportant un jsessionid dans l’URL.
Modifier les règles du firewall pour laisser passer ce type de requêtes aurait introduit une faille de sécurité exploitable par appropriation de session web. Cette faille nous a d’ailleurs été révélée en parallèle par l’outil d’audit de sécurité IBM AppScan.
Ce billet rappelle l’origine du problème et précise quelle solution a été employée pour le résoudre le plus rapidement possible.

Description du problème

Les requêtes HTTP bloquées par le firewall à l’entrée de la DMZ ont le format suivant :

Ces requêtes sont renvoyées par le navigateur lors de la première tentative d’accès d’un utilisateur à l’une des pages d’une application web, à savoir lorsque qu’aucune session web n’était encore créée.

Une analyse plus fine montre que ces requêtes sont émises par le navigateur suite à une demande de redirection 302 effectuée par le framework de sécurité mis en œuvre côté applicatif.
La requête initiale ayant déclenchée la redirection a la forme suivante :

Et voici un exemple de réponse du serveur web :

 Les origines

L’ajout du ;jsessionid=xxx est pris à l’initiative du conteneur web lors de l’appel à la méthode HttpServletResponse::encodeRedirectURL. Bien que pouvant s’apparenter à un bug, ce comportement fait partie intégrante de l’API Servlet. En effet, lorsqu’une nouvelle session est créée, le serveur ne sait pas si le client supporte les cookies et les a activé. Il génère alors un cookie JSESSIONID spécifiant le jsessionid et réécrit ce jsessionid dans l’URL. Lorsque le client émet une seconde requête, le serveur vérifie la présence du cookie. Deux scénarios sont alors possibles :

  1. Lorsque le serveur détecte le cookie JSESSIONID dans la requête, il désactive la réécriture d’URL avec les jsessionid.
  2. Lorsque le cookie JSESSIONID n’est pas transmis mais que l’URL de la requête comporte un jsessionid, le serveur continue à réécrire toute URL en concaténant le jsessionid. Ce comportement s’applique tout au long de la navigation.

Initialement parti d’une bonne attention à l’époque où les navigateurs ne supportaient pas tous les cookies, ce mécanisme de suivi de session pose aujourd’hui plus de problèmes qu’il n’en résout : référencement dans les moteurs de recherche, stockage des URL dans le cache des proxys, déséquilibrage de clusters …
Devenu inutile, IBM l’a par défaut désactivé depuis au moins la version 5 de son serveur d’application Websphere. C’est pourquoi nous n’avions jusque-là jamais rencontré ce problème. Redhat JBoss a mis davantage de temps à se rendre compte de cette problématique de jsessionid référencée sur son bugtracker.

Solutions

Pour contrer ce problème, plusieurs solutions existent.
Certaines ne s’appliquent pas à nos contraintes d’environnements :

D’autres solutions nécessitent de modifier, releaser puis relivrer l’ensemble des applications web :

La solution finalement retenue consiste à exploiter le module mod_headers du serveur Apache 2.2 situé en frontal des JBoss. Alors que le mod_rewrite ne peut agir que sur les requêtes HTTP,  le mod_headers peut modifier les en-têtes des réponses HTTP. Toutes les en-têtes Location comportant un ;jsessionid= sont réécrites sans le  ;jsessionid=

Pour se faire, le module mod_headers a été activé dans le fichier de configuration Apache htppd.conf :

La ligne suivante a ensuite été ajoutée dans le fichier de configuration de l‘hôte virtuel  vhost.conf :

La réponse précédente réencodée par le mod_headers donne :

La redirection GET http://www.monapli.com/index.faces n’est plus bloquée par le firewall.

Conclusion

Rapide à déployer, ce palliatif a permis d’adresser le plus grand nombre des applications.
Pour une  poignée d’entre elles, l’ajout du filtre de servlet a été nécessaire car aucune redirection n’était effectuée lors du premier accès à l’application. La page HTML rendue côté serveur comportait directement des liens comprenant le fameux jsessionid, la méthode HttpServletResponse::encodeUrl étant appelée par les différents tags positionnés sur la page.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *