Protéger Zimbra contre SSL Beast

Parmi les applications web qui font volontiers usage du cryptage SSL / TLS, hormis l'incontournable paiement en ligne, on trouve les serveurs de messagerie de type webmail.
Par nature cet accès aux boites mail via une interface web peut compromettre la confidentialité des données à caractère privé (voir la législation française sur le secret des correspondances) ou des mots de passe utilisés.

La sécurisation des webmails est donc un enjeu d'importance, toutefois ces systèmes sont parfois très intégrés, utilisant un serveur web packagé voir propriétaire.
Dès lors comment se protéger contre la vulnérabilité BEAST que nous avons déjà abordé ?

Voici un exemple concret, concernant un système collaboratif dont une version est disponible en "open source" (et donc gratuitement) : Zimbra (ZCS pour Zimbra Collaboration Suite plus exactement).
Zimbra est un serveur collaboratif offrant essentiellement la fonctionnalité de serveur de messagerie, adossé à une puissante application webmail. Il offre aussi des services de calendrier partagé et de carnet d'adresses.
De multiples fonctionnalités peuvent être ajoutées sous forme de plugins appelés "Zimlets".

Connexion au client Web Zimbra

C'est essentiellement un savant assemblage d'outils libres (postfix pour le serveur de messagerie, clamav et spam assassin pour le filtrage des mails, gestion et stockage de paramètres via serveur LDAP, etc...).
Le résultat est un logiciel puissant et flexible, taillé pour l'entreprise, et qui peut se frotter à des colosses comme Microsoft Exchange et son client Outlook Web Access.
L'acquisition de Zimbra par VMWare il y a quelques années n'est donc pas le fruit du hasard, ni le fait que l'opérateur Free le propose comme interface de consultation de sa  messagerie.

Les versions actuelles de Zimbra sont configurées pour accepter un maximum de navigateurs, et notamment via l'usage d'un large éventail de suites de chiffrement pour l'utilisation en HTTPS.
Si cela va bien entendu dans le sens d'une plus grande compatibilité, le revers de la médaille est sa vulnérabilité à BEAST dans la configuration par défaut.

Bien que le problème ait été évoqué dans les forums Zimbra, le souci semble peu émouvoir pour le moment, et aucune solution simple n'est officiellement proposée.

La solution qui vient à l'esprit serait de modifier les réglages du serveur web utilisé par Zimbra de manière à n'utiliser qu'une poignée de protocoles, notamment RC4.
Malheureusement il semble que ceux qui ont tenté cette opération n'aient pas été couronnés de succès. De plus les fichiers de configurations sont écrasés à chaque mise à jour, créant des difficultés à protéger le système dans la durée.

Je vous propose donc deux autres voies :

  • La première consiste à utiliser un réglage qui permet de modifier les suites de chiffrement autorisées, afin d'obtenir le résultat attendu en ne gardant que celles qui permettent de se protéger correctement.

Je n'ai pas retenu ni testé cette solution, elle semble toutefois assez simple efficace et pérenne.
Si vous êtes intéressé par cette méthode, je vous propose de commencer ici : Cipher suites.

Ce Wiki explique comment modifier les suites de chiffrement autorisées par Zimbra, et contient des liens vers les différentes suites de protocoles et les noms qui leurs sont associés.

On n'oubliera pas de vérifier en utilisant l'outil de SSLLabs

Si vous avez mis cette solution en œuvre, je suis curieux d'avoir votre retour en commentaires !

  • La méthode que j'ai retenue est celle du reverse-proxy, que j'utilise déjà pour d'autres besoins.

En effet nous avons vu précédemment comment rendre un serveur Apache 2 résistant à Beast d'une part, et comment utiliser le reverse-proxy d'autre part.

Pourquoi ne pas combiner ces deux solutions pour proposer un accès sécurisé au webmail ?
Cette modification implique une modification minimale dans Zimbra, et vous laisse le contrôle des réglages via le reverse-proxy.

Première étape

Si nous partons d'un serveur Zimbra configuré de manière simple en serveur HTTPS sur le port 443, il faut d'abord s'atteler à faire en sorte que ce soit le reverse-proxy Apache qui écoute sur le port 443, puis fasse suivre les communications vers le serveur Zimbra.

Nous allons donc commencer par changer le port d'écoute HTTPS de Zimbra :

su - zimbra
zmprov ms monserveur.domain.com zimbraMailSSLPort 4443
zmcontrol restart

La première ligne permet de se loguer en tant qu'utilisateur "zimbra" (faute de quoi les commandes suivantes ne seront pas reconnues).
Puis on change effectivement le réglage de port d'écoute pour HTTPS, et finalement on redémarre le serveur pour que les changements soient pris en compte.
L'exemple retenu utilise le port 4443, mais l'on aurait pu en utiliser un autre, du moment qu'il est libre.

ATTENTION ! Ce réglage est malheureusement remis à la valeur par défaut (443) lors d'une mise à jour de Zimbra, il faut donc penser à la remodifier à chaque mise à jour.

Si votre serveur n'était pas configuré pour utiliser HTTPS ou que vous voulez changer le mode (HTTP seul, mixte, redirection ou HTTPS seul) n'oubliez pas d'utiliser la commande zmtlsctl comme expliqué ici.

Par exemple pour permettre l'accès via une URL HTTP tout en s'assurant que les utilisateurs seront redirigés sur la version HTTPS :

zmtlsctl redirect
zmcontrol restart

... en oubliant pas de se placer sous l'utilisateur zimbra au préalable !

Seconde étape

Elle consiste à configurer Apache pour le reverse-proxy, commençons donc par mettre le serveur en écoute sur le port 443 :

NameVirtualHost *:443

<VirtualHost *:443>
ServerAdmin [email protected]
ServerName monserveur.domain.com

Puis on met le mode SSL en route, et on l'active pour le reverse-proxy... (Pensez à adapter les chemins vers les fichiers en fonction de votre configuration).

SSLEngine on
SSLProxyEngine on
SSLCertificateFile /etc/ssl/certs/ssl.crt
SSLCertificateKeyFile /etc/ssl/certs/ssl.key
SSLCACertificateFile /etc/ssl/certs/ca.pem
SSLCertificateChainFile /etc/ssl/certs/intermediate.ca.pem
SSLProxyCACertificateFile /etc/ssl/certs/ca_bundle.crt

On n'oublie pas de sélectionner les suites de chiffrement RC4 qui vont bien pour éviter la vulnérabilité BEAST :

SSLHonorCipherOrder On
SSLCipherSuite RC4-SHA:HIGH:!ADH

Il nous faut ensuite configurer de manière un peu plus précise pour Zimbra :

RequestHeader set Front-End-Https On
ProxyRequests Off
ProxyPreserveHost On
ProxyVia full
ProxyIOBufferSize 65536

Quelques commentaires sur ces lignes :

  • La première ajoute un entête HTTP qui permet d'indiquer à Zimbra qu'il est derrière un reverse proxy HTTPS.
    Ce n'est pas forcément nécessaire à ce stade, mais ça ne fait pas de mal, et ça deviendra crucial par la suite.
  • La ligne suivante interdit l'usage d'Apache en proxy "direct" (ce qui est plus que recommandé pour éviter de servir de proxy "publique").
  • Les deux lignes suivantes ne sont pas indispensables :
    La directive ProxyPreserveHost On permet de laisser l'information "host" originale dans la requête envoyée vers le serveur Zimbra. Par défaut Apache utilise le nom d'hôte vers lequel se fait la redirection. Cela pourrait être utile dans le cas où l'accès au serveur Zimbra est possible via différentes URL.
    De même la ligne consigne ProxyVia ajoute des informations dans l'entête sur qui permettent au serveur final d'avoir des informations sur les proxies traversées et leur capacités.
  • La directive ProxyIOBufferSize 65536, elle est recommandée afin de prévoir un buffer suffisamment grand pour les réponses à traiter venant de Zimbra, les pages pouvant être assez longues suivant le contenu à afficher.

On termine la configuration de manière classique :

<Proxy *>
Order deny,allow
Allow from all
</Proxy>

Ce qui autorise les accès à la reverse-proxy (on veut qu'elle soit accessible par tous, pas de filtrage).

ProxyPass / https://monserveur.domain.com:4443/
ProxyPassReverse / https://monserveur.domain.com:4443/

Les directives de reverse proxy en elles-mêmes, avec le renvoi vers l'URL du serveur Zimbra sur le port défini auparavant.

On n'oublie pas traiter le log pour les erreurs et on clôture la section de cet hôte virtuel :

ErrorLog /var/log/apache2/monserveur.error.log
</VirtualHost>

On redémarre le serveur Apache, et en principe Zimbra est accessible en HTTPS, tout en étant protégé de Beast, ce que l'on peut vérifier en utilisant l'outil de SSLLabs.
N'oubliez pas d'activer les bons modules dont mod_ssl, mod_proxy et mod_proxy_http !

Il pourra être souhaitable d'empêcher un accès direct au serveur Zimbra sur le port 4443, en utilisant une règle de firewall dans iptables par exemple.

Si cette solution fonctionne parfaitement, elle n'est pourtant pas tout à fait optimale :
En effet dans le cas présent, le reverse proxy apache "termine" la connexion SSL en décryptant le flux, puis effectue son opération de reverse-proxy vers un serveur HTTPS.

Cela oblige à ré-encrypter la connexion et à la re-décrypter du côté du serveur Zimbra, ce qui est assez lourd en ressources, CPU notamment.

On peut certainement se passer de cette deuxième phase de cryptage, à moins d'être totalement parano...
... à la condition bien sûr que le lien entre le reverse-proxy et le serveur Zimbra soit "de confiance" (c'est probablement le cas surtout si les deux éléments sont sur la même machine).

Dans le cas ou les deux services sont sur la même machine, on se contente de faire pointer le reverse proxy vers une version HTTP du serveur Zimbra.
En plus du gain en terme de performances, on s'affranchit de la gestion du certificat SSL côté Zimbra (ou presque, puisque l'on va surement le garder pour l'interface d'administration, et les protocoles IMAPS ou POP3S le cas échéant).

Allons-y !

On configure le port HTTP de Zimbra sur une valeur différente de 80 (facultatif) :

su - zimbra
zmprov ms monserveur.domain.com zimbraMailPort 8080
zmcontrol restart

On force Zimbra en HTTP :

zmtlsctl http
zmcontrol restart

Et l'on configure Apache 2 en conséquence (notez que j'ai retiré les lignes facultatives) :

NameVirtualHost *:443
<VirtualHost *:443>
ServerAdmin [email protected]
ServerName monserveur.domain.com
SSLEngine on
SSLProxyEngine on
SSLCertificateFile /etc/ssl/certs/ssl.crt
SSLCertificateKeyFile /etc/ssl/certs/ssl.key
SSLCACertificateFile /etc/ssl/certs/ca.pem
SSLCertificateChainFile /etc/ssl/certs/intermediate.ca.pem
SSLHonorCipherOrder On
SSLCipherSuite RC4-SHA:HIGH:!ADH
RequestHeader set Front-End-Https On
ProxyRequests Off
ProxyIOBufferSize 65536
<Proxy *>
Order deny,allow
Allow from all
</Proxy>
ProxyPass / http://monserveur.domain.com:8080/
ProxyPassReverse / http://monserveur.domain.com:8080/
ErrorLog /var/log/apache2/monserveur.error.log
</VirtualHost>

La directive RequestHeader set Front-End-Https On est ici importante, elle informe Zimbra que l'utilisateur final utilise une connexion SSL via un reverse proxy, ce qui permet à Zimbra de s'adapter à cette situation.

Et voilà, notre serveur Zimbra est fonctionnel, il est disponible en HTTPS via le reverse-proxy Apache, et l'on est protégé de BEAST.

Mission accomplie ?
Presque !
Tout d'abord il faudra probablement s'assurer que l'on n'autorise pas l'accès directement en HTTP sur le port (ici 8080) via une règle de firewall par exemple.
Ensuite, si nous avions mis en place la redirection HTTP vers HTTPS dans Zimbra, c'est désormais à Apache qu'incombe cette tâche... ajoutons donc la redirection dans notre configuration :

<VirtualHost *:80>
ServerAdmin [email protected]
ServerName monserveur.domain.com
Redirect permanent / https://monserveur.domain.com/
</VirtualHost>

Et nous en avons terminé !

Pour aller plus loin :