I'm using Asterisk 13.1.0 as packaged by Ubuntu Server 16.04 to run a pure-VoIP phone system. Asterisk has a module –
phoneprov – that allows it to template out configuration files for specific lines and serve them from its builtin HTTP server. I'd like to use it to provision my Polycom IP phones, but I can't figure out how to do so securely. Complicating things further, I'm already using the builtin HTTP server for SIP over WebSockets.
As far as I can tell, the
phoneprov module has no authentication or authorization mechanisms at all. It seems to just serve any file to anybody who asks. Since the generated config files contain all the credentials needed to register as a line, anyone who can make HTTP requests to the builtin HTTP server can register as any line provisioned via
phoneprov. That seems like way too obvious a security issue to exist in software as high-profile as Asterisk with nary a peep about it in the documentation or even (as far as I can tell) on the Internet at large. Am I missing something here?
TLS Mutual Authentication
The ideal way, at least in my opinion, to authenticate hardware IP phones for provisioning is via TLS client certificates. Nearly all major manufacturers ship their phones with a client certificate signed by a private CA that identifies the phone by its MAC address. Since the configuration files are also served by MAC address, it's pretty trivial to match the MAC from the certificate to the MAC in the URL and control access that way.
That's what my nginx-based provisioning server (which handles all of the configuration other than line credentials) does. Asterisk, however, doesn't support TLS client authentication for anything ever. It has one common implementation of a socket listener for TCP and TLS, and I've confirmed by reading the source code that it doesn't support requesting client certificates.
tcpctls system does support client certificate verification, but it can only verify that the client certificate is valid and (optionally) that its
commonName matches the client's hostname. While that option can be enabled for the Asterisk HTTP server, it doesn't help much with securing
phoneprov as that module doesn't use the hostname (or anything else) for authorization. It would also break SIP over WebSockets.
Failing the ability to use TLS auth, it would make sense to use HTTP Basic Authentication to secure access to configuration files. The credentials to access the provisioning server would themselves have to be provisioned somehow, but it would be better than nothing.
Unfortunately, I've confirmed by reading the source code that while Asterisk's HTTP server supports HTTP Basic auth, the
phoneprov module does not make use of that capability.
Authentication by Reverse Proxy
If Asterisk can't authenticate requests for itself, I want to use a reverse proxy like nginx to handle authentication before the request even gets to Asterisk. That would be especially convenient in my case as I already have nginx configured to authenticate provisioning clients. Unfortunately, there are two major issues with that approach:
First, Asterisk doesn't support the
X-Forwarded-For header or any other means of discovering the real client IP address when used behind a reverse proxy. I've confirmed this by inspecting the source code. All requests in Asterisk will appear to be from
127.0.0.1 when a reverse proxy is used. That wouldn't be the end of the world for
phoneprov, but the SIP over WebSockets implementation is on the same server and incorrect client IP addresses cause serious issues for SIP. There's no way to separate the SIP over WebSockets server from the
phoneprov server, and the
phoneprov server can't be exposed to the Internet or the reverse proxy is pointless.
Second, even if the client IP issue isn't a problem, it's difficult to secure local access to the Asterisk HTTP server because it only supports listening on TCP sockets. When using a reverse proxy for authentication, the connection between the proxy and the backend needs to be secured to prevent attackers from bypassing the proxy. When the proxy and backend are on the same machine it's common to use UNIX domain sockets for that connection so it can be secured with filesystem permissions. That approach isn't possible with Asterisk, and it's very difficult to secure TCP sockets, even ones bound to
127.0.0.1, against access by unauthorized local processes such as a compromised PHP application.
Avoid HTTP Entirely
phoneprov module also supports exporting its generated files to the filesystem. It would be acceptable to do that and then serve them via another web server that can authenticate the clients like my existing nginx provisioning server, albeit less convenient given the need to regenerate them on change. However, that approach only provides security if the files aren't also accessible unauthenticated via the Asterisk HTTP server.
Unfortunately, based on my reading of the source code, there doesn't seem to be any way of preventing
phoneprov from serving its files over HTTP short of disabling the Asterisk HTTP server entirely, which I can't do because I need it for SIP over WebSockets.
I want to use Asterisk's
phoneprov module to provision my hardware phones, but I can't find any way to secure access to its generated config files. That's obviously unacceptable since those files contain SIP credentials. Is there something I'm missing here? Is anyone using
phoneprov in production? How are they securing it?