How to Develop a Secure Android App

Amrit Lal Sahu
6 min readApr 3, 2020

--

Photo by Brett Sayles from Pexels

In order to preserve user trust and maintain data integrity, developing secure mobile application is one of the major challenge for most of the mobile app developers. This article will take you through some of the best practices that should be followed while building Android app to avoid security vulnerabilities.

1. Maintain Secure communication with other apps

A. Use implicit intents to show app chooser that provides option to user to launch at least two possible apps on the device for the requested action. This allows users to transfer sensitive information to the app that they trust.

B. Apply signature-based permissions while sharing data between two apps that is controlled by you. These permissions do not need user confirmation, but instead it checks that the apps accessing the data are signed using the same signing key. Hence offer more streamlined and secure user experience.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapp">
<permission android:name="my_custom_permission_name"
android:protectionLevel="signature" />

C. Non-exported content providers — Unless you intend to send data from your app to other apps, explicitly disallow other apps to access your ContentProvider in manifest using android:exported=”false”(by default it is “true” for Android version lower than 4.4 ).

2. Secure Network communication

Ensure network security with Security with HTTPS and SSL — For any kind of network communication we must use HTTPS (instead of plain http) with proper certificate implementation. For details please refer here.

Secure connection with server can be established in following ways:

A. Communication with web server having well-known trusted CA certificate does need any additional steps to take while creating the http request.

val url = URL("https://www.google.com")
val urlConnection = url.openConnection() as HttpsURLConnection
urlConnection.connect()
urlConnection.inputStream.use {
...
}

B. By adding a network security configuration: If your app uses new or custom CAs, you can declare your network’s security settings in a configuration file. This process allows you to create the configuration without modifying any app code.

To add a network security configuration file to your app, follow these steps:

i) Declare the configuration in your app’s manifest:

<manifest ... >
<application
android:networkSecurityConfig="@xml/network_security_config"
... >
<!-- Place child elements of <application> element here. -->
</application>
</manifest>

ii) Add an XML resource file, located at res/xm/network_security_config.xml.

Specify that all traffic to particular domains should use HTTPS by disabling clear-text:

<network-security-config>
<domain-config cleartextTrafficPermitted="false">
<domain includeSubdomains="true">secure.example.com</domain>
...
</domain-config>
</network-security-config>

During the development process, you can use the <debug-overrides> element to expliticly allow user-installed certificates. This element overrides your app's security-critical options during debugging and testing without affecting the app's release configuration. The following snippet shows how to define this element in your app's network security configuration XML file:

<network-security-config>
<debug-overrides>
<trust-anchors>
<certificates src="user" />
</trust-anchors>
</debug-overrides>
</network-security-config>

C. Create your own trust manager If web server has a certificate signed by a new or custom CA which is not trusted by the mobile device and additionally you cannot use a network security configuration.

For this scenario, you may need to set up a trust manager and handle all SSL warnings that occurs .

D. Certificates Pinning :Application can be limited to accept only a set of certificates by either limiting the set of CAs they trust or by certificate pinning.

It is achieved by providing a set of certificates by hash of the public key (SubjectPublicKeyInfoof the X.509 certificate). A certificate chain is then valid only if the certificate chain contains at least one of the pinned public keys.

Other scenarios : There are some other factors that should be considered when your application tries to access data through internet:

i. Use WebView objects carefully : The WebView objects in your app shouldn't allow users to navigate to sites that are outside of your control.Additionally, JavaScript interface support should be enabled only if you completely control and trust the content in your app's WebView objects.

Use HTML message channels instead of evaluateJavascript() to communicate between a website and your app.Check the Android documentation to see how to secure your WebView.

ii. Use High-Level Authentication : Authentication mechanisms plays a crucial role in the mobile application security. Sensitive information can be secured efficiently through multi factor authentication,a robust session management and a disconnected system. . It is also essential to set up advanced authorization with the support of tools such as OAuth 2.0 or JSON web tokens for added security of Android apps.

3. Provide the right permissions

App should request only the minimum number of permissions necessary to function properly.

It should not add a permission to complete an action that could be completed in another app. Instead, use an intent to defer the request to a different app that already has the necessary permission.

For example, If an App requires to create a contact to a contact app,delegates the responsibility of creating the contact to a contacts app, which has already been granted the appropriate WRITE_CONTACTS permission.

4. Security on data storage

Cryptography is the most efficient way to achieve data security. Hence, Use appropriate Encryption mechanism while dealing with data inside app. To achieve greater key security, use the Android Keystore system. Please find a nice article on Encryption here.

Following describes the best practices for storing data in your device.

A. Storing private data within internal storage

Store all private user data within the device’s internal storage, which is sandboxed per app. There is no need to request permission to access these files, and cannot be accessed by other apps. Whenever the user uninstalls an app, the device deletes all files that the app saved within internal storage.Consider working with EncryptedFile objects, which are available from the Security library, instead of File objects.Find the example here:

B. Use external storage cautiously

By default, the Android system doesn’t enforce security restrictions on data that resides within external storage, and the storage medium itself isn’t guaranteed to stay connected to the device. Therefore, apply the following security measures to provide safe access to information within external storage.

Use scoped directory access: If your app needs to access only a specific directory within the device’s external storage, use scoped directory access to limit your app’s access to a device’s external storage accordingly.

Access app-specific files: If a file doesn’t contain private or sensitive information but provides value to the user only in your app, store the file in an app-specific directory on external storage.

C. Store only non-sensitive data in cache files

To provide quicker access to non-sensitive app data, store it in the device’s cache. For caches larger than 1 MB in size, use getExternalCacheDir(); otherwise, use getCacheDir(). Each method provides you with the File object that contains your app's cached data.

D. Use SharedPreferences in private mode

To create or access your your app’s SharedPreferences objects using getSharedPreferences(), use MODE_PRIVATE so that your app can access the information within the shared preferences file.

Moreover, EncryptedSharedPreferencesshould be used for more security which wraps the sharedpreferences class and automatically encrypts keys and values.

5. Keep dependencies and libraries up-to-date to make these points of communication more secure.

6. Shrink, obfuscate, and optimize your code with the R8 compiler

If you are building your project using Android Gradle plugin 3.4.0 or higher, the plugin no longer uses ProGuard to perform compile-time code optimization. Instead, the plugin works with the R8 compiler to handle the following compile-time tasks:

Code shrinking (or tree-shaking): detects and safely removes unused classes, fields, methods, and attributes from your app and its library dependencies (making it a valuable tool for working around the 64k reference limit).

Resource shrinking: removes unused resources from your packaged app, including unused resources in your app’s library dependencies.

Obfuscation: shortens the name of classes and members, which results in reduced DEX file sizes.

Optimization: inspects and rewrites your code to further reduce the size of your app’s DEX files.

Conclusion:

These are the best practices that every mobile app developer must follow to secure the app from vulnerability. This helps you in developing highly secure apps required to prevent valuable user information of your app and maintain trust of your client.

--

--