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!
Best Answer
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.