Publié par

Il y a 10 ans -

Temps de lecture 13 minutes

Sécuriser Tomcat 5 derrière un proxy Apache 2 HTTPS

Configurer Tomcat 5 derrière un proxy Apache avec HTTPS, dit comme ça, le novice éclairé pourrait croire que c’est facile. Cependant les problèmes dus à de mauvaises configurations sont nombreux et parfois difficiles à diagnostiquer comme les boucles infinies de redirection par exemple. Donc facile oui (maintenant), mais il m’a fallu plusieurs heures de sueur avant de trouver, non pas une, mais deux solutions. L’avantage de ces deux techniques est de n’utiliser que le driver SSL d’Apache pour fournir le protocole HTTPS. Notez bien cette distinction, car il est facile d’avoir la configuration Apache HTTPS en proxy de Tomcat 5 HTTPS. Toute la difficulté est d’avoir une configuration pleinement fonctionnelle dans laquelle Apache HTTPS est proxy de Tomcat 5 HTTP. Cela permet de sniffer les paquets entre le frontal Web et l’application métier, tout en évitant de doubler les ressources utilisées pour encrypter et décrypter les données.

Un détail pour ceux qui utilisent le mod_jk, le projet Apache Httpd propose depuis Apache 2.0, le module mod_proxy qui permet notamment d’assurer la liaison Apache-Tomcat. Ce module, complété en version 2.2 de mod_proxy_balancer pour le load balancing, supporte les protocole HTTP (mod_proxy_http) et AJP 1.3 (mod_proxy_ajp). Si AJP a longtemps été le protocole utilisé par Tomcat en production, il est aujourd’hui possible, plus simple et plus fiable d’utiliser HTTP. HTTP est notamment recommandé par Mark Thomas et Philip Hanik, SpringSource, qui sont les plus gros contributeurs du projet Tomcat en ce moment.
Si vous êtes habitués à mod_jk, vous apprécierez notamment la simplicité d’un module embarqué par la distribution standard de Tomcat, la fin des interrogations sur la fermeture des connexions en présence d’un firewall entre Apache et Tomcat ou encore le débuggage avec un sniffeur réseau comme wireshark pour voir passer en clair les requêtes HTTP.

Prérequis

Nous passerons les étapes fastidieuses de création des certificats déjà largement documentées à travers le net. Vous devez donc être muni d’une installation Apache déjà fonctionnelle en HTTP comme en HTTPS. Pensez aussi à vérifier que le mod_proxy_http est bien installé et chargé au démarrage d’Apache. Puisqu’il s’agit de Tomcat 5, récupérez aussi la dernière version (Tomcat 5.5.28 actuellement). A priori, ce tutoriel est valide pour toutes les versions de Tomcat 5.5 mais je l’ai uniquement testé sur la version sus-mentionnée.

Voilà, c’est à peu près tout, en dehors de l’application web à tester. Par manque de temps, je ne vous proposerai pas d’application web de démonstration. A vous donc de choisir le war que vous allez tester.

Configurer le proxy Apache HTTP

L’objectif de cette étape est d’avoir accès à travers Apache, sur le port 80, à notre application web testapp, hébergée par Tomcat. Nous allons donc configurer un proxy Apache redirigeant les requêtes HTTP sur le contexte /testapp vers le contexte du même nom, sur le port 8080 du Tomcat. Pour que tout reste clair, j’ai choisi de considérer que Tomcat et Apache sont sur la même machine à l’adresse IP 192.168.42.42, vous devrez donc remplacer à chaque fois qu’elle apparaît cette IP par celle de votre machine. N’hésitez pas non plus, à remplacer l’utilisation de l’adresse IP par celle d’un nom de domaine DNS pour plus de flexibilité.

Apache

Tout d’abord, assurez-vous que le mod_proxy et le mod_proxy_http sont bien chargés au démarrage. Vérifiez dans le fichier httpd.conf ou dans les fichiers de chargement de modules que ces deux lignes sont bien présentes et dé-commentées :


LoadModule proxy_module libexec/apache2/mod_proxy.so
LoadModule proxy_http_module libexec/apache2/mod_proxy_http.so

Attention, ces lignes sont issues de mon httpd.conf sous OS X, les chemins et l’extension peuvent donc varier selon votre système. Recherchez le terme mod_proxy dans les fichiers de configuration d’Apache. Si vous ne le trouvez pas, alors vous devrez sans doute installer le module par vous-même.

Il faut créer un hôte virtuel qui recevra les requêtes sur le port 80 et les passera au serveur Tomcat. Créez d’abord le fichier proxyTomcat.conf

#
# proxyTomcat.conf Proxy Server directives.
#


    ProxyRequests Off       # Le proxy n'est accessible que pour les urls définies
    ProxyPreserveHost On    # Conserver le nom d'hôte d'origine dans la requête

        # Rediriger les requêtes sur /testapp vers http://192.168.42.42:8080/testapp
    ProxyPass    /testapp    http://192.168.42.42:8080/testapp
        # Ajuster les URL de la réponse HTTP du serveur Tomcat
    ProxyPassReverse /testapp http://192.168.42.42:8080/testapp


Si vous êtes totalement novice en configuration Apache, commentez les balises IfModule en plaçant un # en début de ligne. Ces commandes permettent à Apache de ne prendre en compte les paramétrages dans la balise que si le module est bien présent. Si vous les commentez et que le module n’est pas disponible, Apache vous remontera un problème de configuration à son prochain démarrage.

La balise VirtualHost crée un hôte virtuel qui va nous permettre d’isoler la configuration du proxy pour le port 80. Cela nous apporte la garantie que seules les requêtes arrivant sur ce port utiliseront notre configuration. Si les directives ProxyPass* sont placées en dehors d’un hôte virtuel, elles s’appliqueront quelque soit le port de connexion 80/443 en entrée. Ce qui sera totalement transparent en HTTP, mais vous causera de sérieuses difficultés dès que vous accéderez au serveur par HTTPS.

Copiez le fichier dans le répertoire contenant les fichiers chargés au démarrage d’Apache. Là encore, si vous ne trouvez pas où copier le fichier proxyTomcat.conf, placez-le à côté de votre httpd.conf. Éditez ensuite le fichier httpd.conf et ajoutez-y, à la fin, la ligne :

Include chemin/absolu/vers/proxyTomcat.conf

Attention : Apache utilise ‘/’ comme séparateur de fichier sous Windows, le chemin devrait ressembler à c:/apache2/conf/proxyTomcat.conf. Vous pouvez aussi rechercher la directive Include contenant un chemin finissant par .../*.conf pour déterminer le répertoire où stocker notre fichier de configuration.

Pour éviter tout problème, vous pouvez aussi vérifier que l’hôte virtuel default:80 n’existe pas déjà. Le cas échéant, contentez-vous de copier le contenu de notre hôte virtuel à la fin de celui qui existe déjà.

Tomcat

Cette étape est la partie facile ! Il suffit d’ajouter deux petits attributs au connecteur du port 8080 de votre server.xml. Éditez le fichier server.xml qui se trouve dans le répertoire conf de Tomcat, et ajoutez-y les attributs proxyPort="80" proxyName="192.168.42.42" au connecteur du port 8080.


Tomcat utilisera la valeur de ProxyPort pour les requêtes traitées par ce connecteur. De la même façon, la valeur de ProxyName sera utilisée comme nom d’hôte du serveur.

Relancez Tomcat et Apache pour vous assurer que les modifications sont bien prises en compte. Testez l’accès à votre application web avec votre navigateur préféré http://localhost/testapp.

Configurer le proxy Apache HTTPS

Pour cette étape, l’objectif est d’accéder à travers Apache en HTTPS à l’application web testapp hébergée par Tomcat. Nous allons donc créer un proxy Apache redirigeant les requêtes HTTPS sur le contexte /testapp vers le contexte du même nom sur le port 8443 du serveur Tomcat. L’utilisation d’un deuxième port nous permettra plus tard de faire la distinction entre les requêtes sécurisées request.isSecure() et les autres.

Apache

Ici, le travail est simple puisqu’il suffit d’ajouter les mêmes directives de proxy que tout à l’heure à la configuration SSL d’Apache.

Il faut d’abord localiser le fichier dans lequel le support SSL d’Apache est configuré. Sur mon mac, c’est dans /private/etc/apache2/extra/httpd_ssl.conf. Pour trouver le nom du fichier, cherchez la ligne Listen 443 ou mieux <VirtualHost _default_:443>. Éditez le fichier et ajoutez à la fin de l’hôte virtuel les lignes suivantes.

#
# HTTPS Proxy Server directives.
#

    ProxyRequests Off       # Le proxy n'est accessible que pour les urls définies
    ProxyPreserveHost On    # Conserver le nom d'hôte d'origine dans la requête

        # Rediriger les requêtes sur /testapp vers http://192.168.42.42:8443/testapp
    ProxyPass    /testapp    http://192.168.42.42:8443/testapp
        # Ajuster les URL de la réponse HTTP du serveur Tomcat
    ProxyPassReverse /testapp http://192.168.42.42:8443/testapp

Notez bien que cette fois j’ai utilisé le port 8443 pour les redirections.

Tomcat

Pour cette partie, il faut juste ajouter un connecteur sur le port 8443 au fichier server.xml de Tomcat.


Vous pourrez affiner la configuration de ce connecteur plus tard. Pour le moment le principal est d’avoir notre accès en HTTPS.

Relancez Tomcat et Apache pour vous assurer que les modifications sont bien prises en compte. Testez l’accès à votre application web avec votre navigateur préféré https://localhost/testapp. Tout à l’air de fonctionner correctement, pourtant, vous vous rendrez vite compte que les redirections entre HTTP et HTTPS finissent en boucle de redirection infinie, n’aboutissent pas, bref ne fonctionnent pas. J’ai eu le problème avec le ChannelProcessingFilter de Spring Security, mais d’une manière générale, tout ce qui utilise la méthode HttpServletRequest.isSecure() sera affecté.

Forcer le retour de isSecure() à true

Premier piège à éviter, passer sur le connecteur du port 8443, l’attribut secure à true. Dans les faits cela pourrait marcher, car avec cet attribut, Tomcat forcera bien la valeur de la propriété secure de la requête. Le problème c’est qu’elle force aussi le chargement du driver SSL pour le connecteur. Attention, dans Tomcat 6 le problème semble avoir été corrigé.

Il existe à ma connaissance deux façons de modifier la requête avant qu’elle ne soit traitée par notre application. La première solution utilise une Valve Tomcat pour modifier la requête en fonction du port de destination (8080 ou 8443). La deuxième solution passe par la création d’un filtre HTTP dans l’application testapp.

Valve Tomcat

Les valves sont des filtres spécifiques de Tomcat fonctionnant en quelque sorte comme des filtres de servlet. Ils ont l’avantage d’être exécutés avant tous les processeurs de requêtes (filtre, servlet, …) et d’être définis pour l’ensemble du serveur et non pour l’application web uniquement.

Nous allons donc créer une valve qui comparera le port de réception de la requête à un paramètre de configuration securePort. S’ils sont égaux, la valve passe secure à true et scheme à HTTPS pour que l’illusion soit parfaite. Elle finit en invoquant l’exécution du filtre suivant.

package fr.xebia.tomcat;

import java.io.IOException;
import java.util.logging.LogManager;
import java.util.logging.Logger;

import javax.servlet.ServletException;

import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.apache.catalina.valves.ValveBase;

/**
  * Valve passant les requetes sur le port {@link SecurePortValve#securePort}, en mode securise
  * 
  * @author slm
  * 
  */
public class SecurePortValve extends ValveBase {

    /**
      * Par defaut le port securise est le 8443
      */
    private int securePort = 8443;

    private static final Logger LOG = LogManager.getLogManager().getLogger(SecurePortValve.class.toString());

    public void setSecurePort(int securePort) {
        this.securePort = securePort;
    }

    public int getSecurePort() {
        return securePort;
    }

    /**
      * execution du filtre
      */
    public void invoke(Request req, Response resp) throws IOException, ServletException {
        LOG.info("Invocation de la valve pour securiser le port "
                 + securePort + " pour une requete sur le port " + req.getLocalPort());
        if (req.getLocalPort() == securePort) {
            req.setSecure(true);
            req.setScheme("https");
            LOG.info("La requete vient du port securise: Passage de secure a true");
        } else {
            LOG.info("La requete ne vient pas du port securise.");
        }

        if (getNext() != null) {
            getNext().invoke(req, resp);
        }
    }

}

Vous pouvez récupérer ici le projet maven et ici le jar que j’ai utilisé pour les tests. Copiez le jar dans le répertoire server/lib de Tomcat. Il faut maintenant ajouter la valve à la configuration du serveur. Éditez le fichier server.xml et insérez avec les autres Valve de la balise Engine, la ligne suivante.


Reste à croiser les doigts, redémarrer Tomcat et vérifier que cela fonctionne correctement. Notez que j’ai volontairement mis les logs en info dans le code pour avoir un retour rapide sans plus de configuration. Supprimez-les, ou passez-les en debug une fois les premiers tests réalisés avec succès.

ServletFilter

Pour cette solution il suffit de monter un filtre décrit dans le web.xml. Le filtre quand il sera exécuté, fera approximativement la même chose que la Valve, à savoir comparer le port de réception à une valeur de configuration securePort. Si les deux valeurs sont égales, notre filtre substituera la requête d’origine par un objet HttpServletRequestWrapper qui surchargera les méthodes isSecure() et getScheme(). L’avantage de cette technique est d’obtenir une solution portable qui ne s’appliquera qu’à l’application web sans nécessiter de reconfigurer le serveur Tomcat.

package fr.xebia.tomcat;

import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.Logger;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

/**
  * Filtre de servlet permettant de passer la requete en mode securise sur la base du port de réception.
  * 
  * @author slm
  */
public class SecurePortFilter implements Filter {

    private static final String SECURE_PORT_PARAM_NAME = "securePort";

    private static final Logger LOG = LogManager.getLogManager().getLogger(SecurePortFilter.class.toString());

    private int securePort = 8443;

    public void destroy() {
    }

    /**
     * Filtrage des requetes pour passer en mode securise sur les requetes venant du port {@link SecurePortFilter#securePort}
     */
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {

        if (req.getLocalPort() == securePort) {
            if (LOG.isLoggable(Level.FINEST)) {
                LOG.log(Level.FINEST, "La requete vient du port securise " + securePort
                        + ", on positionne secure a true et scheme a 'https'");
            }
            if (req instanceof HttpServletRequest) {
                req = new HttpServletRequestWrapper((HttpServletRequest) req) {

                    public boolean isSecure() {
                        return true;
                    }

                    public String getScheme() {
                        return "https";
                    }
                };
            }

        }

        chain.doFilter(req, resp);

    }

    /**
     * Chargement du parametre de configuration {@link SecurePortFilter#securePort}
     */
    public void init(FilterConfig config) throws ServletException {
        String paramValue = config.getInitParameter(SECURE_PORT_PARAM_NAME);
        if (paramValue != null) {
            try {
                securePort = Integer.parseInt(paramValue);
            } catch (NumberFormatException e) {
                LOG.log(Level.WARNING, "La valeur " + paramValue + 
                        " du parametre d'initialisation " + SECURE_PORT_PARAM_NAME
                        + " n'est pas un entier valide !", e);
            }
        }
        LOG.info("Les requetes venant du port " + securePort + " seront securise");

    }
}

Notez bien le test réalisé avec l’opérateur instanceof. Le risque était de perdre des informations liées au type HttpServletRequest. Donc je teste le type avant de construire un HTTPServletRequestWrapper et d’invoquer le filtre suivant de la chaîne. Pour tout dire, j’avais des erreurs remontées par les OncePerRequestFilter de Spring que nous utilisons dans le projet pour gérer le chargement des locales notamment.

Si vous avez fait le test avec la SecurePortValve et que vous désirez maintenant utiliser le SecurePortFilter, pensez avant toute chose à commenter la ligne qui active son utilisation dans le server.xml. Intégrez ensuite le filtre à votre application. Vous pouvez copier le jar récupéré plus haut dans le répertoire WEB-INF/lib de votre application, le mettre en dépendance dans votre pom Maven ou simplement recopier le code dans vos sources. Il faut ensuite ajouter la configuration du filtre dans le web.xml. Attention, nous voulons que SecurePortFilter soit le premier filtre exécuté de la chaîne pour garantir que la requête sera bien sécurisée en amont de tous nos traitements. Éditez le web.xml et ajoutez avant le premier mapping de filtre les lignes suivantes.


    
        securePortFilter
        fr.xebia.tomcat.SecurePortFilter
        
        	securePort
        	8443
        
    
    
        securePortFilter
        /*
    

Redéployez l’application et vérifiez que tout fonctionne. A ce stade, vous avez une configuration complètement fonctionnelle en HTTP et en HTTPS avec le serveur Apache en frontal devant Tomcat.

Aller plus loin

Commencez par savourer votre succès, un peu d’auto-statisfaction ne fait pas de mal. Parmi les possibilités, vous pouvez déporter Apache ou Tomcat sur une autre machine, ou même utiliser des noms de contextes différents grâce au ProxyPassReverse d’Apache. Avec le mod_proxy_balancer vous pourrez aussi configurer Apache pour faire de la répartition de charge sur un cluster de serveurs Tomcat.

Publié par

Commentaire

16 réponses pour " Sécuriser Tomcat 5 derrière un proxy Apache 2 HTTPS "

  1. Publié par , Il y a 10 ans

    Bonjour,

    J’aimerais bien savoir quel sont les arguments qui iraient en faveur du mod_proxy/HTTP plutôt que le mod_jk/AJP. Mon expérience est plutôt qu’on préconise le second, et on essaie de gérer le premier s’il y a des impératifs externes (dus aux contraintes du SI des clients) qui le nécessitent.

    Par exemple, en utilisant mod_proxy au lieu de mod_jk, il y a un problème d’architecture si on veut un utiliser HTTPS avec authentification client (et non plus authentification serveur uniquement), c’est-à-dire pour faire de l’authentification forte. En effet, si la connexion entre Apache et Tomcat est en HTTP, il n’est pas possible de récupérer au niveau de Tomcat, et donc au niveau applicatif, les informations du certificat client, donc a fortiori, son authentification.

    Je me permet de réagir, parce que j’ai fréquemment eu à faire du support, voire à écrire des contournements applicatifs parce que cet impératif (et non pas choix) d’architecture a été imposé sur des projets.

  2. Publié par , Il y a 10 ans

    Bonjour et merci pour ces commentaires,
    effectivement, plusieurs arguments ont déjà été avancés sur ce choix. J’ajoute tout de même que contrairement au mod_proxy, le mod_jk ne fait pas parti de la distribution officielle d’Apache. La configuration est aussi beaucoup plus simple avec le mod_proxy. Notez ensuite que le protocole AJP n’est pas aussi répandu que le protocole HTTP. L’utilisation d’un proxy HTTP est donc portable vers des solutions ne supportant pas AJP. Quelque soit le backend, la même configuration pourra être appliquée, ce qui simplifiera grandement le travail d’administration.
    Dernier avantage déjà mentionné dans l’article, avec HTTP il est facile d’analyser le trafic entre le frontend et le backend ce qui n’est pas possible avec un protocole binaire comme AJP.

  3. Publié par , Il y a 10 ans

    Intéressant, et les arguments en faveur de mod_proxy paraissent fondés. Cependant quelqu’un a t’il une réponse à apporter à la question de Benoît portant sur l’authentification forte et la propagation du certificat client jusqu’à Tomcat ?

  4. Publié par , Il y a 10 ans

    Bonjour et merci pour ce petit rappel à l’ordre.

    Pour assurer l’authentification des certificats clients avec le mod_proxy_http, il faut tout d’abord activer la dite authentification sur le proxy apache. Avec Apache il est tout à fait possible de forcer la présentation d’un certificat client valide. Cela a le mérite de sécuriser correctement l’accès aux pages sans pour autant remonter les informations utiles du certificat au niveau applicatif. Pour contourner ce problème, il suffit d’utiliser le mod_headers qui va permettre d’ajouter dans les entêtes de la requête les informations du certificat dont l’application a besoin.

  5. Publié par , Il y a 10 ans

    [cite Séven Le Mesle]
    Cela a le mérite de sécuriser correctement l’accès aux pages sans pour autant remonter les informations utiles du certificat au niveau applicatif. Pour contourner ce problème, il suffit d’utiliser le mod_headers qui va permettre d’ajouter dans les entêtes de la requête les informations du certificat dont l’application a besoin.
    [/cite]

    Cela présente les inconvénients suivants :
    – devoir faire une configuration spécifique (pour le mod_headers) au cas où il y a des attributs du certificat spécifiques à une infrastructure donnée ;
    – il faut modifier l’applicatif en fonction de l’infrastructure, puisque quelque chose de standard (le certificat qu’on récupère par request.getRemoteUser() …) devient quelque chose de spécifique (request.getHeader(« myCertifiedUserLoginKey »)).

    En ce qui concerne les arguments présentés dans les slides de Covalent (merci pour le lien très intéressant), je suis sensible à ceux expliquant que HTTP c’est du texte (donc lisible pour l’éternité et autre avantages), et que c’est un standard tellement répandu qu’il existe pléthore d’outils permettant de travailler avec, mais j’ai du mal à croire que l’overhead du mod_http par rapport au mod_jk soit négligeable parce qu’on a moins de travail de marshalling/unmarshalling. Quand j’avais fait des tests (il y a six ans, soit, et dans une configuration bien précise !) le gain à utiliser mod_jk était tel que l’on ne pouvait même pas se poser la question (du simple au double, de mémoire, en gros).

  6. Publié par , Il y a 10 ans

    Bonsoir Benoît,
    pour ce qui est de l’utilisation d’attributs de certificats spécifiques, je ne saurai me prononcer. J’avoue ne pas avoir beaucoup utilisé ce type d’authentification. Dans le même registre, je n’ai pas fait les benchs pour comparer les performances des deux modules. Je peux juste dire que dans la documentation actuel de Tomcat, il est recommandé d’utiliser le mod_jk pour améliorer les performances précisément. Cela dit, la performance de la solution utilisant le mod_proxy doit pouvoir être au moins amélioré en utilisant la compression gzip pour limiter la quantité de données qui transite entre les deux serveurs.
    Par contre, je pense qu’il est parfaitement envisageable d’appliquer la même méthode que dans l’article pour assurer que le remoteUser soit renseigné correctement sur la requête.

  7. Publié par , Il y a 10 ans

    @Séven

    Vous m’avez persuadé qu’il faut que je refasse une analyse en partant sur les versions actuelles pour reévaluer les arguments en faveur de l’une ou l’autre option.

    Quoiqu’il en soit merci pour l’article.

    Remarque :
    Websphere contient en interne un fork d’une version antérieure de Apache (IHS) et Tomcat (Websphere à proprement parlé), et la communication entre les deux est assurée en HTTP + spécifique (comme le mode proxy dont on parle), comme le mod_proxy.

  8. Publié par , Il y a 10 ans

    Ayant contribué quelques années à mod_jk, j’ai lu cet article avec intérêt. Je m’interroge souvent sur ce rejet de mod_jk qui est souvent décrié alors qu’il fonctionne bien et permet des configurations très diverses, du simple lien HTTP->Tomcat jusqu’à des modes load-balancing très élaborés.

    Le seul manque de mod_jk est la découverte de la topologie d’une grappe de Tomcat distantes et l’ajustement dynamique à l’entrée/sortie de membres dans la grappe et ce sont des points qui ne sont pas couverts par mod_proxy mais plutôt par le projet JBoss mod_cluster (http://jboss.org/mod_cluster/).

  9. Publié par , Il y a 9 ans

    Pour info, sur les certificats clients, une des differences entre mod_jk et mod_proxy est que mod_proxy ne fait passer que le premier certificat de la chaine envoyee par le client (le certificat client lui-meme), et pas toute la chaine (alors que mod_jk le peut):

    http://www.mail-archive.com/dev@httpd.apache.org/msg41660.html

    (Ca n’est un probleme que si on a besoin de la chaine, bien sur.)

  10. Publié par , Il y a 8 ans

    Bonjour et merci pour votre article que j’ai lu avec attention.
    J’aimerais savoir quel est l’intérêt de sécuriser Tomcat de la manière décrite dans cet article ?
    En effet, il me semble (sauf si j’ai loupé qqchose) que la communication entre Apache et Tomcat reste du HTTP et donc que les données sont transmises en clair, non ? Si c’est le cas, quel est l’apport de la sécurisation décrite ici ?
    Je me pose la question car je dois mettre en place une appli avec un serveur apache en frontal de 2 tomcat qui héberge des webapps dont l’accès (au niveau applicatif) est sécurisé par spring-security (via login/password et ldap), et donc dans mon cas, les données d’authentification sont transmises jusqu’au Tomcat.
    Merci d’avance.

  11. Publié par , Il y a 8 ans

    Bonjour Mathieu,

    tout d’abord Apache est bien plus performant pour traiter le SSL que Tomcat. Cela permet donc de soulager les serveurs Tomcat de traitement lourd, ensuite, personnellement je considère que dans ce type de configuration, les serveurs Tomcat sont dans un réseaux de confiance en dehors de la DMZ et donc que les données sensibles ne sont pas mises en péril.
    Les login et mot de passe peuvent très bien être transmis au Tomcat dans le cas présenté ci-dessus c’est d’ailleurs ce que j’avais fait à l’époque chez mon client. J’utilisais aussi Spring-Security pour réaliser l’authentification.
    Encore un avantage que je trouve à cette configuration, est de simplifier très largement l’analyse en cas de problème car dumper une requête HTTP en clair permet de voir réellement ce qui se passe entre les serveurs.
    Je conseillerai tout de même de faire attention aux logs car on retrouve très facilement les login et mot de passe qui y apparaissent.
    Typiquement si vous faites du GET pour l’authentification avec les paramètres dans l’URL, par défaut ils apparaîtront dans les access log Tomcat.

    Merci d’avoir lu cet article et merci encore pour cette question.

  12. Publié par , Il y a 8 ans

    Bonjour,
    Merci pour l’article,il m’a permis de mettre en place mon serveur apache sécurisé lié a tomcat et tout marche comme sur des roulettes avec toutes mes applications simples : jsf, jsp, servlet. Donc avec https://localhost/MonApp me renvoie MonApp avec toutes ses pages sous https.
    Cependant, avec une application d’architecture prévoyant acegi pour l’authantification,j’ai un problème:ça ne marche pas.
    En effet, selon les navigateurs, voici mes résultats avec https://localhost/MyAppli:

    Chrome: Bad Request
    Your browser sent a request that this server could not understand.
    Reason: You’re speaking plain HTTP to an SSL-enabled server port.
    Instead use the HTTPS scheme to access this URL, please.
    Hint: https://localhost/

    Firefox:

    400 Bad Request

    Bad Request
    Your browser sent a request that this server could not understand.
    Reason: You’re speaking plain HTTP to an SSL-enabled server port.
    Instead use the HTTPS scheme to access this URL, please.

    Hint: https://localhost/

    Internet Explorer:
    Ici une première alerte arrive disant:  » Vous etes sur le point de visualiser des pages sur une connexion sécurisée … » et je clique sur ok
    Aussitôt après, une deuxième alerte s’érige: « La connexion que vous allez utiliser n’est pas sécurisée… » et je clique sur ok ya rien qui s’affiche juste du blanc.

    La constante dans les trois navgateurs est que si je continue a enfuire manuellement, entre trois a quatre fois,https au début des urls ou je suis redirigé, le reste de mes pages est sécurisé https exemple: https://localhost/MyAppli/transaction.jsp
    Maintenant j’aimerai bien que vous me donniez une idée car ca fait des jours que je suis bloqué à ce niveau.

  13. Publié par , Il y a 8 ans

    Bonjour,
    Merci pour l’article; il m’a permis de mettre en place ssl dans mon serveur apache en frontal lié à tomcat. Ainsi toutes mes applications simples (avec jsf,jsp,servlet) marchent et me renvoient le résultat attendu de l’url https://localhost/MonApp.
    Cependant, tout n’est pas rose car avec mon application qui prévoit une architechture acegi pour l’authentification, je n’arrive pas à avoir de résultat et pour les deux navigateus chrome et firefox voici le meme résultat:

    Bad Request
    Your browser sent a request that this server could not understand.
    Reason: You’re speaking plain HTTP to an SSL-enabled server port.
    Instead use the HTTPS scheme to access this URL, please.
    Hint: https://localhost/

    pour Internet explorer

    une alerte est déclenchée disant: « vous êtes sur le point d’accéder a des pages par une connexion securisée … » et je clique sur « ok »
    Aussitôt après, une deuxième alerte s’érige: « la connexion que vous allez utiliser n’est pas sécurisée ».

    Toutefois, la constante dans les trois navigateurs est que si continue à enfuire manuellement « https » (pendant trois a quatre fois) au début des urls oû je suis redirigé, toutes mes pages sont sous https et je n’ai plus besoin de les rentrer manuellement: quand j clique sur un lien ou bouton l’url est directement https?

    Si vous avez rencontré ce problème, ce serait volontier que j’accepte votre aide. Merci

  14. Publié par , Il y a 7 ans

    Bonjour,

    Souhaitant abandonner le proxy_ajp pour utiliser le proxy_http, et étant en https côté Apache je suis tombé sur votre article (bien référencé).

    Notez que je suis en tomcat6.

    Autant j’ai dû utiliser des valves pour conserver l’IP du client, récupérer l’attribut REMOTE_USER via un request.getRemoteUser() (comme le permet de base le connector AJP), …

    Autant pour le https il m’a suffit (en plus du PreserveHost au niveau apache) d’ajouter au Connector HTTP
    scheme= »https » proxyPort= »443″

    Sans cela effectivement, et malgré le ProxyPassReverse, le PreserveHost à On provoque des redirections http/https circulaires comme vous l’avez décrit.

    Je n’ai pas eu à utiliser secure= »true », il faut dire que je ne suis pas sûr que mon application utilise un request.isSecure()

    Cet article reste très intéressant (merci !), mais je pense que les configurations natives du connector http tomcat devraient pouvoir suffir la plupart du temps pour ce cas d’usage « apache https en proxy d’un tomcat via http »
    http://tomcat.apache.org/tomcat-5.5-doc/config/http.html

    Bien cordialement.

  15. Publié par , Il y a 5 ans

    Bonjour,

    Tout d’abord merci pour l’article, j’ai beaucoup appris ! Je suis stagiaire dans une société qui utilise cette solution et je développe une application dans laquelle je dois récupérer l’adresse ip du client or il semblerait que ce fameux proxy apache ne veut pas me la donner ! J’ai déjà essayé pas mal de solutions comme le getRemoteAddr, getRemoteHost, getHeader(« X-Forwarded-For »), getHeader(« Proxy-Client-IP »), getHeader(« HTTP_X_FORWARDED_FOR ») mais sans succès aucuns ! Si vous avez une solution fiables à me confier je suis preneur car je suis un peu désemparé à récupérer l’adresse ip du client…

    Bien cordialement,
    Rémi

Laisser un commentaire

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

Nous recrutons

Être un Xebian, c'est faire partie d'un groupe de passionnés ; C'est l'opportunité de travailler et de partager avec des pairs parmi les plus talentueux.