UCP behind apache as reverse proxy


#1

Hi,

I need some help to setup remote access to Freepbx 14 UCP via a apache reverse proxy.

Expected : https on port 443 to the apache server then http to the internal freepbx.

Error Message: Unable to connect to the UCP Node Server. Error: xhr poll error

Any help is welcome.
Andre.


#2

Personally I use haproxy with strict-sni on , something like

global
.
.
.
defaults
.
.
.


frontend http
  mode http
  bind *:80
  bind *:443 ssl strict-sni crt /etc/haproxy/certs/ 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-SH
A:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4
  tcp-request content accept if { req.ssl_hello_type 1 }
  http-request redirect scheme https unless { ssl_fc }
  tcp-request inspect-delay 5s                                                                                                                                                             

  acl ucp ssl_fc_sni ucp.your.domain.com
  use_backend ucp if ucp
.
.
.
backend ucp
  server ucp 127.0.0.1:8084 maxconn 2048
.
.
.


that way http to the named site (http(s)://ucp.your.domain.com in this case but it could easily be just http(s)://your.domain.com) gets re-directed to https and haproxy supplies the TLS certs then connects to your apache server (on port 8084 in this case, but no certs needed) , however http or https connections to your bare ip address just get essentially useless, to a hacker, replies (ERR_SSL_UNRECOGNIZED_NAME_ALERT)

You can add other frontend/backend pairs for other services like admin on provisioning and you are not limited to your primary URL domain which is generally leaked by dig -x 12.34.56.78 that way you can use your own 'secret domain ( less than $10 a year from namecheap) for the most sensitive web traffic, which would be much harder to penetrate.

Effecively you are swapping one domain name with multiple ports open to multiple domains with only 80 and 443 open


#3

You can (and should) ensure that a reverse lookup of your IP address does not yield any useful info. However, certificates are public record so a secret domain must have a secret 2nd level name.

For example, it does little good to have supersecret.mydomain.com if the attacker can determine that your main domain is mydomain.com; he can look up all your subdomains at e.g.
https://transparencyreport.google.com/https/certificates
(check the Include subdomains box) and iterate through them.

For resources such as admin GUI and UCP, you can work around this issue by having a certificate for *.mydomain.com but have the server only accept requests for supersecret.mydomain.com. Unfortunately, this usually does not work for provisioning, because most IP phones don’t handle wildcard certificates properly.


#4

In my scenario your ‘other domain ’ might well be stuntedantelope.live’ and the admin interface only available at https://yellowzzyyx.stuntedantelope.live and the https provisioning at https://eggsbenedictation.stuntedantelope.live, fop2 however at https://fop2.mydomain.com all the above A records point to the external IP of your VOIP server

You are right in that certificates are easily checkable if you know the name, but these more sensitive sites are specifically NOT subdomains that the dig -x or just a connection to https://11.22.33.44 or https://mydomain.com would reveal. The strict-sni clause kinda important. There are no wildcards needed.


#5

Unfortunately, many older IP phones don’t support SNI. Using a secret host name (checked by the server) is almost as good, but requires manual server configuration.


#6

The phones don’t ‘need’ sni support, if they are pointed at https://eggsbenedition.stuntedantelope.live they will be transparently proxied to the provisioning server (which only serves http, haproxy handles the TLS handshaking) . If they are very old they might need sslv3 support enabled.


#7

But if the default cert offered by the proxy is for other than eggsbenedition.stuntedantelope.live , the phone would have to be configured to not verify the cert (some might not even have that setting), while if it is for eggsbenedition.stuntedantelope.live, then the attacker learns the provisioning domain.


#8

There’s the beauty of haproxy, in this case there is no default certificate. Only certs will be exchanged IF there is a frontend (URL) that is matched by an ACL, under which circumstance haproxy will tender the relevant certificate from your defined crt-base directory , commonly /etc/haproxy/certs/ if no match and strict-sni is on the connection will get an abrupt ‘NO server here’ with no other info divulged.

An added benefit is that you can issue a cert for 9001.stuntedantelope.live or 9001.extensions.blackmamba.live and have its backend redirect to extension 9001’s built in web server at 192.168.45.77:80 or as appropriate.


#9

Sorry, I don’t understand what you mean. If a phone opens a TLS connection and doesn’t supply SNI, then the server either rejects the connection (phone doesn’t get provisioned), supplies the cert the phone expects (leaks info to an attacker), or supplies a bogus cert (that the phone would probably reject). There is simply no way to see the Host header from the phone without presenting a cert.


#10

By example, curl -vv https://eggsbenedition.stuntedantelope.live will show the relevant transactions. eggsbeneditation.stundedantelope.live IS effectively the ServerNameIdentification that haproxy will use to match, present the relevant certificate and then fetch if it passes muster, there is a one-to-one mapping of URL to backend server here so the sni extensions to TLS are not a concern of the phone, just the proxy. No matching URL no connection proxied, your provisioning server will never see a thing. A potential attacker would have to already have ‘leaked’ info to even know to attack eggsbenedictation. . ., but that’s another subject that a good conntracker in your firewall should make short shrift of (think Fail2Ban)

Perhaps you could try it, it shouldn’t take you more than an hour or so, if you did, watching the haproxy log is in itself a good learning experience with its likely plethora of '<NOSRV>' and ‘SSL handshake failure’ lines amidst the legitimate proxy forwards.

Peer review always appreciated.

edit:-

I will try to clarify , the initial TLS handshake always starts in http/1.1 mode so will always include the ‘server_name’ in cleartext, this is what chooses the certificate and thus the backend but the strict-sni conditional will only return to the client a certificate If there is a matching frontend with matching ACL , without it, then indeed more info will be leaked. otherwise just a 503 error.

Haproxy is not a webserver but if using http mode, fully processes TLS negotiation. The client/haproxy traffic will be encrypted https but in this scenario the haproxy/server traffic is back to http, so now open to MITM exploits but of course this is now all LAN bound.

tcpdump -An port 443 or port 80|egrep "com|org|net|live|link|. . ."

will quickly reveal the raw server_names received, /var/log/haproxy.log a more readable trace.


#11

Thanks all for your reply.

Basically I just want to open the possibility to set/unset : DND and call forwarding. Including from a mobile.
So no need service like WebRTC for now.

With a classical proxy config seems to do the job but with frequent red popup like " Unable to connect to the UCP Node Server. timeout".

Any config to avoid that ?

My current workaround is to add a proxy rule to forward port 8003 to PBX port 8001

Thanks.


#12

That’s not a workaround, it’s the solution if you want some clients to have access the node server. Pretty sure it’s an all-clients or no-clients thing. Some network-awareness, or just an “always ignore” option in the popup to save the setting in a client-side cookie would be worth opening an Improvement/New Feature ticket.

If you don’t need any client to have the functionality, try disabling the node server in Advance Settings.
If you still get the pop-ups with the node server disabled, I would consider it a bug and a you should absolutely open a bug ticket.