Security Tips for Android Developers

Lucas Aquino
4 min readSep 13, 2023

--

Mobile applications have a huge impact on society and how we interact with the real world. Nowadays we're developing applications to buy food, use public transport, control our cars, monitor and interact with our houses, control our finances, and many other cases. While all this kind of modernization brings us a positive impact we need to be careful when dealing with data provided by our users and make sure that we're using it in a safe way. This article tries to provide some security tips that we should have as Android developers.

Certificate Pinning

Is a security technique used to prevent the theft or forgery of certificates. The Certificate Pinning works by storing the server’s digital certificate in a secure location locally in the device, for example in KeyStore. The application then checks the server’s digital certificate before establishing a connection. The application will not establish the connection if the digital certificate is invalid.

The Certificate Pinning protects the application from MITM (Man In The Middle) attacks. The safest approach is pinning a leaf certificate instead of trusting in root CA or intermediate CA. It will make it absolutely certain that your application will only communicate with the server that has the specified certificate.

When pinning a leaf certificate, provide a backup pin like an intermediate CA. The downside is that providing an intermediate CA increases the risk but also reduces the chances of a problem that could be catastrophic: an issue with your leaf certificate could make your application unable to communicate with your server. Providing a backup pin makes your application fall back to intermediate CA until your team releases a new application update.

How to Pin

From Android N the recommended approach is pinning using Android’s Network Configuration, which lets us customize the network security in our application using a configuration file. Check more details in the official documentation. Since this approach is only supported from Android N, you can also check how to set up Certificate Pinning using OkHttp or TrustKit-Android library.

URL Loading in WebViews

Since WebView is used to load HTML and JavaScript content in the application, it must be used and configured properly to avoid security issues. For example, you must be very careful when using addJavaScriptInterface() because it allows JavaScript to call operations normally reserved for Android applications.

Maybe the most important thing is to make sure that WebViews in your application only loads trusted content. This can be achieved by preventing the WebView from loading any URL that is not a trusted domain, this can be done by overriding the WebViewClient method as below:

webView.webViewClient = object : WebViewClient() {
override fun shouldOverrideUrlLoading(
view: WebView,
request: WebResourceRequest
): Boolean {
/**
* Check if request.url.host is in your list of trusted domains.
* Must return true to avoid the URL to be loaded, otherwise return false.
*/
return false
}
}

webView.loadUrl("https://www.yourdomain.com")

Misconfigured Google Firebase

In the last year, Check Point Research (CPR) found thousands of mobile applications exposing sensitive data from users in cloud-based databases. This problem was detected in misconfigured Firebase rules which provide unnecessary access to application data like Firebase Realtime Database.

Is important to keep in mind that the initial rules configurations might work for development but should not be used for production. You must make sure that the Firebase data is not available for public access. Here you can find all the details about the risk and how to set properly your Firebase project to protect the data from public access.

Implicit Intents

Since Android has two categories of Intents: explicit and implicit Intents we should be very careful when handling implicit Intents. Explicit Intents can be delivered only to a predetermined component that can be an activity, service, or receiver because we must set a receiver (app package name and the class that will handle it).

With implicit Intents, we only pass certain parameters like data, mime type, and action and we're not able to specify the component to call because Android itself decides which component should be called. In this case, the data can be leaked to third-party applications installed on the device because any application can register to intercept implicit Intent.

This potential problem can affect Activity launches, Broadcasts Receivers, and Services for example. So we really need to avoid using implicit Intents, if you need to pass implicit Intents to other applications, make sure that you're not passing any sensitive data in Intent and if you're expecting to receive any kind of data from a component called you must validate the received data to avoid use malicious data internally in your app.

Cryptography

Since each application runs isolated from other apps the data used by our apps is safe, right? NO!

We always must encrypt sensitive data stored by our application but we need to make it the right way. So we must avoid having any encryption key hardcoded, the right way is to encrypt data on Android using Keystore introduced in Android 4.3.

If you need to add one more security layer over the communication between your application and your API you could store a public key in Keystore, use it to encrypt the data and your server can use the private key to decrypt the data.

Extra tip: always delete all data related to the user and encryption key after the user logs out.

--

--