Here:

In the first example, a valid host, valid sni. Second is valid sni broken host. Third is totally made up sni with broken host. Fourth is a valid Host with a made up sni. The apache vhosts have separate log files. The ssltest.example.ca sni with ssltest-broken.example.ca properly logs to the ssltest log. The valid host ssltest.example.ca made-up-sni, logs to the app2 vhost (default) logfile. So pretty sure the Host header is being totally ignored here.

printf "GET / HTTP/1.1\r\nHost: ssltest.example.ca\r\n\r\n" | openssl s_client -connect internal.app2.example.ca:443 -servername ssltest.example.ca CONNECTED(00000003) depth=2 O = Digital Signature Trust Co., CN = DST Root CA X3 verify return:1 depth=1 C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3 verify return:1 depth=0 CN = *ssltest*.example.ca verify return:1 printf "GET / HTTP/1.1\r\nHost: ssltest-broken.example.ca\r\n\r\n" | openssl s_client -connect internal.app2.example.ca:443 -servername ssltest.example.ca CONNECTED(00000003) depth=2 O = Digital Signature Trust Co., CN = DST Root CA X3 verify return:1 depth=1 C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3 verify return:1 depth=0 CN = *ssltest*.example.ca verify return:1 printf "GET / HTTP/1.1\r\nHost: ssltest-broken.example.ca\r\n\r\n" | openssl s_client -connect internal.app2.example.ca:443 -servername made-up-sni.example.ca CONNECTED(00000003) depth=2 O = Digital Signature Trust Co., CN = DST Root CA X3 verify return:1 depth=1 C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3 verify return:1 depth=0 CN = *app2*.example.ca verify return:1 printf "GET / HTTP/1.1\r\nHost: ssltest.example.ca\r\n\r\n" | openssl s_client -connect internal.app2.example.ca:443 -servername made-up-sni.example.ca CONNECTED(00000003) depth=2 O = Digital Signature Trust Co., CN = DST Root CA X3 verify return:1 depth=1 C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3 verify return:1 depth=0 CN = *app2*.example.ca verify return:1


On 2017-07-26 12:49 PM, Willy Tarreau wrote:
On Wed, Jul 26, 2017 at 12:28:55PM -0700, Kevin McArthur wrote:
No, it needs it to select the certificate to present. Then it should match
it against the Host header field, and use the Host header field to select
the vhost. The difference is subtle but it's important to keep each protocol
element one in its role. In the end for HTTP it's always the Host which
decides, regardless of the transport.
Perhaps how it should work but this isn't actually how apache matches vhosts
in a ssl context. They use the SNI, which selects the vhost in use. The host
header can be gibberish and it will still select the vhost via sni when
configured with ServerName directive.
Well it's the first time I hear about this and find this a bit shocking,
as Apache tends to try to follow standards and ignoring Host clearly
doesn't fall into that category and would even cause some security issues
when used as a reverse-proxy by routing the requests to the wrong places.
Also the doc here tends to disagree as well :

    https://httpd.apache.org/docs/2.4/vhosts/name-based.html

     "With name-based virtual hosting, the server relies on the client
     to report the hostname as part of the HTTP headers."

So maybe you want to double-check what happens when you do this :

   $ printf "GET / HTTP/1.1\r\nHost: domain1\r\n\r\n | openssl s_client 
-connect host:port -servername domain2
   $ printf "GET / HTTP/1.1\r\nHost: domain2\r\n\r\n | openssl s_client 
-connect host:port -servername domain1

My guess is that either you'll get a 4xx error because there's a mismatch
or you'll get the domain referenced in the Host header delivered.

And by the way I'm seeing this in their changelog for v2.2.26 and v2.2.27 :

   *) mod_ssl: Check SNI hostname against Host header case-insensitively.

   *) mod_ssl: Do not perform SNI / Host header comparison in case of a
     forward proxy request

This tends to confirm that by default the comparison is performed.

Willy

Reply via email to