Ssl – Issue with HAProxy and SSL/TLS handshake by webserver for different subdomains in same browser session

haproxysessionssl

We have a firewall with a HAProxy (pfSense) and multiple webservers. Every webserver is configured with HTTPS. The HAProxy frontend rules are defined with Server Name Indication TLS extension matches and the webservers are defined as backends (all very similar).

Excerpt HAProxy config (domain/ip replaced)

frontend HAProxy_443-merged
    bind            1.2.3.4:443 name 1.2.3.4:443   
    mode            tcp
    log         global
    option          log-separate-errors
    timeout client      45000
    tcp-request inspect-delay   5s
    acl         sub1example req.ssl_sni -m end -i sub1.example.com
    acl         sub2example req.ssl_sni -m end -i sub2.example.com
    ...
    tcp-request content accept if { req.ssl_hello_type 1 }
    use_backend sub1.example.com_ipvANY  if  sub1example
    use_backend sub2.example.com_ipvANY  if  sub2example
    ...

backend sub1.example.com_ipvANY
    mode        tcp
    id          159
    log         global
    timeout connect     30000
    timeout server      30000
    retries         3
    server          sub1.example.com 192.168.1.80:443 id 160 check inter 1000
...

Everything is working fine for all domains on its own, but there is a problem with some subdomains in the same browser (same root domain, e.g. *.example.com).

Description:

If you are visiting different subdomains in the same browser session in the space of 30 seconds, the traffic is routed to the first webserver/backend. If you are reloading the page, it will renew this unknown session. After approx. 30 seconds this session is closed and you can visit the correct page.

But there are some subdomains without these issue.

BTW: It's not reproducible with tools like Postman.

I investigated the HAProxy settings for front- and backends, I checked response headers and tried to debug the ssl handshake, but I couldn't find a similarity of problematic or difference between working and problematic webserver/backends.

Does anybody recognize this issue? Thanks in advance.

Best Answer

This can happen if multiple internal servers have a multi-domain certificate (or wildcard certificate) where the different domains covered by the certificate are handled by different internal servers.

Consider a certificate which has subject alternative names for both A.example.com and B.example.com. If the client creates a HTTP/2 connection to A.example.com via haproxy it will sniff the initial TLS ClientHello and forward the traffic to server A which is responsible for A.example.com. If then the client accesses B.example.com the browser maybe decide to use the same TCP connection since according to the certificate it is valid for A.example.com but also B.example.com. See RFC 7540 section 9.1.1. Connection Reuse for the relevant part of the HTTP/2 standard which allows this.

Now server A might be unable to handle the request for B.example.com. In this case the server should issue a response with code 421 "Misdirected Request" in which case the client (browser) might repeat the request using a new HTTP/2 connection. If the server does not create such a response the client does not know about the problem and cannot act accordingly.

It is impossible to fix this problem within haproxy since haproxy will only decide where to forward the data based on the initial ClientHello. Instead one has to fix it either by making the server reply with 421 or making sure that the certificates only cover the domains actually served by the server.

See also 421 Misdirected Request and HTTP/2 connection pool breaks SNI hosts.