I recently built a Cordova application with Angular. The application periodically calls a server to get information. One of the requirements was that the client server communication had to be over SSL. I didn’t know much about the SSL protocol but I thought it should be a piece of cake. With most hosting providers it is done in just a few clicks.
But this case is slightly different. The application must function without internet connection. the app communicates with an on site server in a local network by IP address.
In this post I will cover what the main reasons are to use SSL, what problems arise when you want to use SSL in a local network and how I fixed it for a Cordova application. Everything that is described in this post will also work (even better) for native applications.
Why we want to use SSL
The two reasons why we want the app to communicate with the server over SSL are Encryption and Identification.
Encryption is basically hiding what is sent from one computer to another. If a you don’t use SSL, the data will be transmitted as is and any computer on any of the networks between the client and the server can intercept and read the data.
The SSL protocol puts a barrier around the communication. All the data that is sent from the client to the server and vice versa will first be changed before it gets transmitted. The data can still be intercepted by any computer on the network but they can’t read the data. The data is encrypted.
There can be a secure connection, but that does not necessarily mean that the client can trust the computer that is on the other end. To validate the identity of a server the SSL Protocol uses a certificate. In the certificate are details of the receiver/owner. To make the certificate reliable, there is a whole process behind obtaining a certificate. The organization has to communicate with another organization called a Certificate Authority (CA). The organization asks a certificate for a specific domain, the CA will check domain ownership and look up the details of the organization. For some versions the CA will check more information of the business/organization but domain ownership is always mandatory.
If the CA approves the request, they create a certificate for the organization and sign it with their private key. The certificate can than be installed on the server to which the domain points to.
If a client connects through HTTPS to the server, the server sends its public key with its SSL certificate to the client. Once the client gets the certificate it will check the signature to make sure it’s valid. This is done by e.g. checking if it is signed by a trusted CA and the current hostname matches the domain in the certificate.
If all checks succeed, a secure connection will be established. If not, (depending on the client) the request will fail.
To get a valid certificate we need to pass a CA. A certificate belongs to a domain and the CA checks the domain ownership. In a local network we don’t have a domain and we communicate to the server by IP address. Because of this, the domain ownership check cannot take place. A CA will never issue a certificate for a local IP address.
But can’t we just use the certificate of the domain for our organization. We have a valid certificate. We can just installed that one on the server… Fortunately it is not that easy. When setting up the SSL connection, the client also check if the domain matches the domain on the certificate this is called ‘Hostname verification’. We communicate by an IP address, this does not match the domain and the connection fails.
In order for the hostname verification to succeed, our certificate must contain the IP address. We can’t count on a CA so we have to make a certificate ourselves. This is possible and is called a ‘Self signed certificate’. This is a certificate that is not validated and signed by a CA, but by the organization itself. The IP address can be added by adding it as a ‘subjectAltName’ to the certificate. That way the hostname verification will succeed
Earlier we said that the validation of a CA is used in the SSL checks. If the certificate is not signed by a CA that is known by the client, the check will fail. To make sure the client trusts our self signed certificate we need to pin the certificate in the application.
In Cordova certificate pinning is not possible. The server connections are handled by the webview. Therefore it is not possible to intercept SSL connections to perform the check of the server’s certificate. True certificate pinning is only possible in native code. That means that every request must happens through native code instead of traditional XHR/AJAX requests.
To make all this work, we used a cordova plugin to pin the certificate and made sure the application makes all requests using this plugin. For convenience we created an Angular httpClient interceptor that stops the normal requests and delegates it to the plugin.