Authenticating remote servers and encrypting connections
To protect data your app sends over the internet from eavesdroppers the data should be encrypted.
Encryption is notoriously difficult to get right, and so your app should use the built in mechanisms provided by Android:
HttpsURLConnection: for connecting to a web service where the server accepts HTTPS connections.
SSLSocket: for lower-level SSL connections to a server.
Most likely your app will be connecting to a web server using HTTPS, rather than using SSL sockets directly, and so use of the
HttpsURLConnection class is the preferred way to do this.
Both the above methods will also authenticate the server through the use of certificates.
Opening an HTTPS connection
Security risks with the default Certificate Authorities
By default Android will verify the server’s certificate using the system’s inbuilt list of Certificate Authority (CA) root certificates, however this has several problems, some of which are potentially very serious:
The server’s certificate might be signed by a CA that Android does not know about, for example an organisation might decide to use a self-signed certificate for a private server. By default Android would not accept the certificate as valid and instead would throw a
An attacker may be able to create a fake certificate for a server if they have access to a CA’s private key. The fake certificate will be signed by a different CA than the real certificate, but Android (and most other OSs and browsers) will by default accept the fake. All they care about is that the certificate is signed by any of the CAs in their list. This is becoming a very real threat, as if an attacker is able to compromise a CA, then this gives them almost unlimited power to access the contents of encrypted network connections as they can fake any certificate they want: banks, email servers, social media platforms etc. This is not a theoretical risk, it has happened.
Controlling the CA root certificates
The solution to both these problems is essentially the same. An app must take control of the CA root certificates it will trust. In general an app is not a web browser, and will not be expecting to connect to an arbitrary server out on the internet. On the contrary, it will almost certainly be connecting to a small number (often just one) of pre-specified servers. An app can therefore be configured to only accept certificates signed by a specified set of root certificates.
Up until Android 7.0 (API level 24) this was quite hard to do, and required explicit changes to an app’s source code. Indeed, online you will find many examples where people have implemented a custom
HostnameVerifier and often got these badly wrong. This approach is no longer recommended.
Android 7.0 (API level 24) introduces a new Network Security Configuration feature that gently simplifies things. The major improvement is that the network security policy is no longer hardcoded into an app’s source code, but is instead specified in an XML configuration file. This makes it much easier to:
Review the policy and carefully check that the right CA root certificates are specified for each of the servers an app may connect to.
Change the CA root certificates the app trusts if a server’s certificate is changed (for example if the old one expires).
Blocking HTTP traffic
The new Network Security Configuration feature also allows an app to enforce that all traffic to a particular server is sent by HTTPS and not HTTP, thus avoiding accidentally sending data unencrypted.
This is called opting out of cleartext traffic in the Android documentation.
This protects against bugs where a developer accidentally types
http:// in a URL rather than
© University of Southampton 2017