4

I'm setting up my first HAProxy reverse proxy server. It's going to be a proxy for an HTML5 app running on tomcat from a different server. I was able to get it to proxy out via HTTP, redirect all requests to HTTPS, and implement HSTS. However, after doing so I realized that it also tries to load a websocket connection. The problem is that the websocket connection it loads is insecure (ws://) and not secure (wss://). Of course, Chrome (and presumably multiple browsers) complain about loading an insecure script over a secure connection. Here's the error I get:

Connecting via WebSocket using url ws://website.domain.com:9091/webclient/
Mixed Content: The page at 'https://website.domain.com/webclient/' was loaded over HTTPS, but attempted to connect to the insecure WebSocket endpoint 'ws://website.domain.com:9091/webclient/'. This request has been blocked; this endpoint must be available over WSS.
Caught WebSocket error: SecurityError: Failed to construct 'WebSocket': An insecure WebSocket connection may not be initiated from a page loaded over HTTPS.

All of these were loaded by /webclient/script/ajaxclient.js:210

As this is a 3rd party app, I'm not sure if I'm going to be able to get them to change their app. Therefore, I was wondering if there's something I can do on the HAProxy server to force a secure websocket connection. Any thoughts?

Here's my HAProxy conf file for reference:

global
    log         127.0.0.1 local2

    chroot      /var/lib/haproxy
    pidfile     /var/run/haproxy.pid
    maxconn     1000
    user        haproxy
    group       haproxy
    daemon

    # turn on stats unix socket
    stats socket /var/lib/haproxy/stats

    # Default SSL cert locations
    ca-base /etc/haproxy/ssl_2015
    crt-base /etc/haproxy/ssl_2015

    # Default ssl ciphers
    ssl-default-bind-ciphers ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4

    # max size of temp DHE keys that are generated
    tune.ssl.default-dh-param 4096

defaults
    mode                    http
    log                     global
    option                  httplog
    option                  dontlognull
    option http-server-close
    option forwardfor       except 127.0.0.0/8
    option                  redispatch
    option                  http-server-close
    retries                 3
    timeout http-request    10s
    timeout queue           1m
    timeout connect         10s
    timeout client          1m
    timeout server          1m
    timeout http-keep-alive 10s
    timeout check           10s
    timeout tunnel          4hrs                # long timeout for Websocket connections
    maxconn                 3000

#---------------------------------------------------------------------
# http frontend
#---------------------------------------------------------------------
frontend http_https_frontend
    bind 192.168.2.201:80
    redirect scheme https if !{ ssl_fc }
    bind 192.168.2.201:443 ssl crt /etc/haproxy/ssl_2015/ssl_crt.pem
    acl secure dst_port eq 443
    rspadd Strict-Transport-Security:\ max-age=16000000;\ includeSubDomains;\ preload;
    rsprep ^Set-Cookie:\ (.*) Set-Cookie:\ \1;\ Secure if secure

#   # routing based on websocket protocol header
#   acl is_websocket hdr(Upgrade) -i WebSocket
    acl is_websocket hdr_beg(Host) -i ws
    use_backend ws_backend if is_websocket


#    # 16000000 seconds: a bit more than 6 months
#    http-response set-header Strict-Transport-Security max-age=16000000;\ includeSubDomains;\ preload;
    default_backend https_backend

#---------------------------------------------------------------------
# http backend
#---------------------------------------------------------------------
backend https_backend
    reqadd X-Forwarded-Proto:\ https
    server websvr1_http 192.168.1.125:8080

#---------------------------------------------------------------------
# ws backend
#---------------------------------------------------------------------
backend ws_backend
    server websvr1_ws 192.168.1.125:9091

The HAProxy server is a CentOS 7.1.1503 server running HAProxy 1.5.4.

Thanks in advance!

1

As this is a 3rd party app, I'm not sure if I'm going to be able to get them to change their app. Therefore, I was wondering if there's something I can do on the HAProxy server to force a secure websocket connection.

This depends mostly on the 3rd party application. If the application is specifically using the ws: protocol, there is nothing you can do on the HAProxy side - browsers won't even connect to the HAProxy instance, so you aren't ever even given the chance to do anything about it.

You would need to open an issue with the 3rd party application developers and have them make the web socket protocol configurable, or add some detection (if the page is loaded over HTTPS, then use WSS).

Alternatively you could introduce content rewriting, where you have something that modifies outgoing content to re-write ws:/ to wss://. HAProxy cannot do this, but Nginx along with the sub_filter module can.

  • Thanks for your answer @vcsjones. I had assumed that this was the answer, but being unfamiliar with HAProxy, I thought I'd check. – JoeInVT Jul 30 '15 at 17:30

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.