L’utilisation de VirtualHosts séparés en fonction des noms de domaine est très répandue sur les serveurs Apache multi-sites. Il est intéressant de se pencher sur les mécanismes de restriction entre VirtualHosts, notamment dans le cas d’une connexion HTTPS où il y a eu récemment un renforcement de ce mécanisme (à partir de la version 2.4.64 sortie en juillet 2025) qui peut causer des changements de comportement.
Cas d’une connexion HTTP non chiffrée
Même si ce cas est de moins en moins courant, il est intéressant de rappeler le mécanisme de base pour une connexion HTTP non chiffrée : le seul moyen pour Apache de sélectionner le bon VirtualHost lors d’une requête client est de se baser sur l’entête HTTP Host (obligatoire à partir de HTTP/1.1). Voici un exemple avec netcat :
$ echo -e "GET / HTTP/1.1\r\nHost: www.debian.org\r\n\r\n" | nc www.debian.org 80
HTTP/1.1 302 Found
…
En conséquence, dans le cas d’une connexion HTTP, on peut accéder à n’importe quel VirtualHost si l’on connaît les options ServerName et ServerAlias, il n’y a pas spécialement de « restriction ». Évidemment on peut préciser des options dans le VirtualHost comme Require all denied mais c’est un autre sujet.
Rappel du fonctionnement de SNI
Avec HTTPS, il existe l’extension SNI qui consiste à ce qu’une requête client indique un nom de domaine AVANT la partie chiffrement. Cela permet notamment à Apache de sélectionner le bon certificat SSL avant de passer à la phase de chiffrement.
Pour faire une requête avec SNI, on peut utiliser l’option -servername
de la commande openssl s_client :
$ openssl s_client -connect 130.89.148.77:443 -servername www.debian.org
Ainsi si l’on fait un tcpdump, on verra passer en clair « www.debian.org » au début de l’échange :
# tcpdump -s0 -XX -ni any port 443
…
0x00c0: 002f 00ff 0100 00b0 0000 0013 0011 0000 ./..............
0x00d0: 0e77 7777 2e64 6562 6961 6e2e 6f72 6700 .www.debian.org.
0x00e0: 0b00 0403 0001 0200 0a00 1600 1400 1d00 ................
…
Évidemment les navigateurs web modernes utilisent SNI depuis des années, sinon une bonne partie des sites Internet souvent hébergés derrière une même adresse IP ne fonctionnerait pas.
Cas d’une connexion HTTPS
Apache a un mécanisme de restriction pour empêcher d’accéder à un VirtuaHost qui ne correspond pas au SNI présenté. Cela va renvoyer une erreur 421 Misdirected Request :
$ echo -e "GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n" | openssl s_client -connect 130.89.148.77:443 -quiet -servername www.debian.org
HTTP/1.1 421 Misdirected Request
<title>421 Misdirected Request</title>
<h1>Misdirected Request</h1>
<p>The client needs a new connection for this
request as the requested host name does not match
the Server Name Indication (SNI) in use for this
connection.</p>
Pour être précis, cela n’impose pas forcément une correspondance avec le certificat SSL, mais si l’on envoie un entête HTTP Host correspondant à un autre VirtualHost, on sera bloqué.
On peut donc distinguer deux mécanismes distincts :
- Apache va sélectionner le « meilleur » VirtualHost qui correspond au SNI présenté (et lui envoyer le certificat SSL correspondant à l’option SSLCertificateKeyFile du VirtualHost)
- Une fois qu’Apache a sélectionné le VirtualHost, il n’autorise d’utiliser l’entête HTTP Host que pour un nom de domaine valide pour ce VirtualHost (donc dans ServerName ou ServerAlias)
Une particularité c’est le « VirtualHost par défaut » : si l’on indique un SNI qui ne correspond à rien, on va être renvoyé vers le VirtualHost par défaut, que l’on pourra solliciter avec n’importe quel FQDN… sauf ceux présents dans les autres VirtualHosts !
Restriction renforcée à partir d’Apache 2.4.64
Si l’on n’utilise pas SNI, jusqu’ici Apache ne faisait pas de restriction particulière : on est renvoyé vers le « VirtualHost par défaut », et l’on peut solliciter n’importe quel FQDN et accéder à n’importe quel VirtualHost.
$ echo -e "GET / HTTP/1.1\r\nHost: www.debian.org.fr\r\n\r\n" | openssl s_client -connect 130.89.148.77:443 -quiet
HTTP/1.1 200 OK
Mais dans le cadre de la correction de la faille CVE-2025-23048, Apache 2.4.64 a patché (ahah) son code pour étendre la restriction exposée un peu plus haut, voici le patch : https://github.com/apache/httpd/commit/c4cfa50c9068e8b8134c530ab21674e77d1278a2
Le patch est assez simple : le code qui renvoie le 421 Misdirected Request a simplement été déplacé pour s’appliquer aussi au cas sans SNI.
Ainsi, à partir d’Apache 2.4.64, la requête précédente devrait donner :
$ echo -e "GET / HTTP/1.1\r\nHost: www.debian.org.fr\r\n\r\n" | openssl s_client -connect 130.89.148.77:443 -quiet
HTTP/1.1 421 Misdirected Request
Cela n’est pas encore le cas car a priori le serveur hébergeant « www.debian.org » tourne sous Debian 12 (bookworm) avec Apache 2.4.62.
Apache 2.4.65 est la version actuellement présente en Debian 13 (trixie) et dans Debian 11 (bullseye) depuis mi-août (via une mise à jour de sécurité LTS). Apache 2.4.65 devrait arriver dans Debian 12 (bookworm) le 6 septembre 2025 (sortie de Debian 12.12). On peut voir cela sur https://packages.debian.org/apache2
En pratique, chez nous ce changement a nécessité quelques adaptations de configuration :
- Sur certains serveurs HAProxy où l’on se connecte en HTTPS à backend sous Apache, il faut bien activer explicitement le SNI (ce qu’étonnament HAProxy ne fait jamais)
- Sur nos check_http de monitoring où l’on doit parfois ajouter l’option SNI