“Gartner Listed - mobile application security guide”

April 24, 2019

Mobile app security testing checklist – Android

Writing secure mobile application code is difficult. The competing expectations of innovative user interfaces, new operating system features and API changes often leave security at the back of the list. Here at Codified Security we’ve created a mobile app security testing checklist for Android to help you through the security testing process.

A high-level mobile app security testing checklist will help stop companies from being victims of the most critical and exploitable errors. These should be the first port of call for anyone concerned about mobile app security. Many of these recommendations contain links to more detailed articles and comprehensive checks.

1. SSL

A modern SSL implementation supporting TLS 1.2 is essential for app security. Public networks are well known to be insecure and any good developer owes it to their users to encrypt their data and protect their privacy.

Many developers will ignore SSL certificates or hostname errors during development, which is easily forgot and renders SSL useless. To understand how to use SSL securely consider the errors a penetration tester would look for in this checklist. You should also consider implementing certificate key pinning to avoid Man in the Middle attacks.

Android’s SSL support is provided by a Security Provider. A default Provider is provided by the platform, but this can become dated and vulnerable to exploits. To protect against these exploits the platform allows the user to update this provider through Google Play Services. By calling the Google Play Services methods within your app you can ensure that the platform has the latest version installed, protecting your app’s data against known exploits.

To update the Provider you need to use the ProviderInstaller within your application code. This process is quite involved, and is explained in detail in this Android Developer article.

2. Debug Code

The software architectures imposed by the Android UI frameworks don’t lend themselves to easily-testable code, often making debug code and console logging the rule rather than the exception.

Many developers leave their debug code in production. This will still get compiled into the app along with any API calls that it contains. This makes it easy for your web and network infrastructure to be attacked. See the OWASP page on debug code.

If you’re using Gradle to build your Android project you can use the following code in your build.gradle file to generate a custom variable:

buildTypes {

    debug {

        buildConfigField "Boolean", "DEBUG_MODE", "true"

    }

    release {

        buildConfigField "Boolean", "DEBUG_MODE", "false"

    }

}

When building the project gradle should then generate the following code for you:

public final class BuildConfig {

  // Fields from build type: debug

  public static final Boolean DEBUG_MODE = true;

}

You can then reference the variable in your own code to ensure that debug code does not get run in release mode:

if (BuildConfig.DEBUG_MODE) {

    // Add your debug code here

}

3. Console Logging in Production Code

Leaving console logging in production code can be a huge security issue, as this can be read by anyone with access to the device. On some older versions of Android this is particularly problematic as other apps can also read the console logs. This vulnerability is quite simple to pick either using tools or with mobile app security testing.

The worst example of this we’ve seen was a Fintech app that logged to Android on every REST call. This included plain text passwords, CCVs, and addresses. This kind of error would be devastating if it fell into the wrong hands and can also cause PCI compliance issues. Ideally your application should use remote logging and not system logs.

Though debug logging is disabled by default on Android the code inside the logging calls is unfortunately still evaluated, which is both a security issue and a performance problem. For example, given the following code the expensive database call will still be run on release builds:

Log.d(TAG, “Number of users “ + dbClient.users.getAll().count());

To avoid this problem one trick is to use Proguard to strip the code on your behalf. Proguard provides a way to remove calls to specific functions in release mode. Any calls for debugging logs can be removed with following setting in proguard-project.txt.

# Remove debug logs

-assumenosideeffects class android.util.Log {

    public static *** d(...);

    public static *** v(...);

}

4. Web Views

Web views embedded within apps are often sandboxed properly by the operating system and frameworks. This is however web code, so the same rules (XSS, CSRF) apply. A cross-site scripting attack will allow session hijacking and access to the rest of the app.

Android stores the WebView cache unencrypted on the filesystem, so it’s important to avoid caching sensitive information. To avoid caching you can set either set no-cache in the HTTP cache-control headers or ensure that you call clearCache() after using the WebView to delete any local files.

If your HTML doesn’t use JavaScript you should not call setJavaScriptEnabled(). By default the WebView will not execute JavaScript, so cross-site scripting is not possible. In particular you should take extreme care when calling addJavaScriptInterface() as this will expose Android APIs normally reserved for native applications.

Apps running on devices with a platform older than Android 4.4 include a version of webkit containing a number of security issues. As a workaround, if your app is running on these devices it must confirm that WebView objects display only trusted content.

5. App Files

Most apps will need to store persistent configuration information to ensure that the application maintains a consistent state between sessions. Some apps will also read configuration files from the filesystem, or even allow these files to be provided over the air by a back-end system.

In all of these cases data will be stored on the filesystem that could potentially be modified by an attacker. If this data is sensitive it might be more appropriate to move this configuration to the application binary if possible, or to ensure that the data is encrypted.

Android’s SharedPreferences stores data unencrypted on the filesystem. These files are protected by standard Linux-style file permissions, enforcing access to only the application binary. On a rooted device these files are easily accessible however, so you should never store sensitive information here without encrypting it first.

When using SQLite databases for sensitive data one option might be to use SQLCipher, which will encrypt the entire database. Though SQLCipher is a commercial product, there is an open source version available.

6. App Backup

By default an application can be backed-up and and restored using the Android Debug Bridge (ADB) developer tool. The ADB tool allows an attacker to copy the app’s locally-stored data without having root access to the device. To disable the backup capability you need to add android:allowBackup=”false” to the Application section of the app manifest. For more information check out the Android documentation for Auto Backup.

7. Reverse Engineering

Android apps are more prone to reverse engineering than iOS due to their use of bytecode rather than machine code. To avoid this problem you can make use of the Proguard tool, which ships with the Android SDK.

Proguard has many benefits other than obfuscation as it can also strip unused classes, fields, methods, and attributes from your packaged app, including those from included code libraries. As a result it can also help a lot with keeping the app under the 64k reference limit.

Check out the code shrinking article from the Android Documentation for more information on integrating Proguard.

8. App Screenshots

If your app displays sensitive data to the user it’s possible that this data could be captured, either by the user taking a screenshot or the app appearing in the list of recently used apps. To avoid this issue you should set FLAG_SECUREin the LayoutParams of your UI. You should also set the android:excludeFromRecents flag to “true” in the <activity> section of your app manifest.

If this mobile app security testing checklist has got your attention and you want to know more about secure mobile development take at look this OWASP mobile app security checklist and these OWASP resources.

Codified Security is here to help make your mobile app secure whether it’s for iOS, Android, or to make sure you’re clearing the OWASP Mobile Top 10. For mobile app security testing try out Codified Security.