REX logo

LEARN

HOW TO USE REX AND WRITE SECURE CODE
8 bit drawing of Jay

Secure Mobile Application
Development

Part 4: Data Storage

Jahmel Harris, Technical Director

Attack Scenario: 1, 2, 3

Thought should be put into what sensitive data is stored on the device as this may be available to an attacker. Ideally, sensitive information (including passwords, encryption keys, API keys, credit card details etc) should either be stored and received from the server or entered by the user when required. This way, should an attacker be able to view the data stored by the application, nothing of value will be gained. It should be noted that techniques exist to recover application data on both rooted and non rooted devices.

Protecting all sensitive data is often a difficult task as the device may log or cache various bits of information in ways out of our control or in ways we did not anticipate. In order to make sure everything is considered, an expert should provide a checklist of things to disable.

Often, sensitive information relating not to the user, but to the organisation or application developers are available to an attacker once all files are extracted from the IPA (iOS) or APK (android). As these file types are essentially nothing more than a ZIP file, artefacts from the build are often left inside or sensitive information is stored within plaintext files such as the AndroidManifest or plist files. Development URLs, private keys, passwords or even the names and email addresses of developers are often key bits of information an attacker can use and should not be stored within the installation package.

Occasionally an application will need access to an API key to use a web service. When these keys are sensitive and should not be leaked, consider creating a proxy service to access the web service. With this approach, the API key is only available on the proxy service and the normal authentication techniques we use can be used to authenticate the user/mobile application to the proxy.

Data read from the device should never be considered trusted. If a security decision is made on the contents of a file, the integrity of the file should be considered. This can be achieved by using Hashed Messaged Authentication Codes (HMAC) although unless appropriate binary protections are applied, it may be possible for an attacker to modify the binary to accept incorrect values.

Generally, the following should be considered when thinking about whether the data should be stored on the device:

  • Is the data sensitive?
    • Don't store it and instead consider retrieving it from a web service protected by proper authentication.
  • If data is to be stored on the device, encrypt it with a key generated from some user input (such as a passcode or PIN or with Touch ID in iOS 9 and later). The PIN should not be stored.
    • As this may be susceptible to an offline brute-force, there should be no way for an attacker to know whether the data decrypted correctly or not.
    • Strong encryption functions should be used.
  • Data should not be trusted. It should be assumed it can be modified at any time.
  • Don't trust the security of the device. If the device is rooted, all security controls may fail. If a security control has a vulnerability, an attacker may be able to bypass it to access sensitive information.
  • Understand the platform - data can be logged without our knowledge.
  • Logs can be read by someone with physical access to the device or remotely given the right privileges.
iOS

Screenshots

In order to improve perceived performance, iOS will screenshot an application as it goes into the background (stored in the applications Library/Caches/Snapshots/<Bundle ID> directory). When the application is in the task switcher or relaunches, iOS will display the screenshot. When launching, from a user's point of view the application is ready to use immediately. In reality, until the application finishes loading the Operating System is only displaying the last image of the application as it was put into the backgrounded state.

This is something to be aware of as any application that displays sensitive information (such as banking details, user tokens or encryption keys) can inadvertently leak that data by this process. These are the recommended ways to address this issue:

  • Don't display anything sensitive on screen. If this is not possible, sensitive information should be obscured by the application (e.g. by asterisks)
  • If sensitive data should be on screen, make sure it is obscured by an image or by setting the Hidden attribute on the control. This can be achieved displaying a splash screen in the applicationDidEnterBackground function as this function is called when an application is about to go into the background. This should be reversed in applicationWillEnterForeground. Sample code can be found here.

Web Cache

As many apps use web services or embed web controls, it's likely sensitive information will be cached. Often, this can include passwords, credit card details, session tokens and more. Data can be cached in several locations and so care should be taken to make sure caching is disabled or cached data is removed.

iOS provides many ways of specifying the cache should not be used (including specifying the Cache-Control: no-cache HTTP Header) but many approaches can and will be ignored by iOS under specific edge cases and so should not be relied upon. As well as disabling caching by setting setDiskCapacity and setMemoryCapacity to 0 in applicationDidFinishLaunch the Cache directory should be manually deleted. NSCachesDirectory can be used to get the cache directory.

Local Storage

Local storage is an HTML5 mechanism that is used to store offline data for use within a web based application. As this is present within the applications cache directory (/Library/Caches/*.localstorage). As anything stored in the HTML5 local storage database could be read by an attacker with either physical access or malware running on the target device, care should be taken to store nothing sensitive within the local storage database.

If this cannot be done and there is a requirement to store sensitive data for the user to access offline, risk can be lowered by storing the data in a newly created database encrypted using the Data Protection API. This will encrypt the file based on a the users PIN and will grant access to the encrypted file in different scenarios depending on the protection level used.

User Preferences

The NSUserDefaults class can be used to store data related to the user's preferences related to the application such as how often a document is saved or how information should be displayed. As data is not encrypted (outside of the standard iOS encryption) this data would be available to an attacker if the application is backed up (including in iCloud) or if running the application on a jailbroken device. Because of this, nothing sensitive should be stored using the NSUserDefaults class. Instead, the keychain or encrypted database should be considered should sensitive data need to be stored locally.

Keychain

The keychain is an encrypted database meant for storing sensitive data such as passwords, session tokens and other small pieces of information that should only be available to our application. Although the encryption used to secure the keychain is strong, it is possible to read the keychain on a jailbroken device.

When storing data in the keychain, care should be taken to make sure the data is protected with at the appropriate level. There are several options available, listed here from most secure to least:

  • kSecAttrAccessibleWhenUnlocked - Available when the device is unlocked.
  • kSecAttrAccessibleAfterFirstUnlock - Available after the passcode is first used after after a reboot.
  • kSecAttrAccessibleAlways - Available when device is locked.
  • kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly - Available when the device is unlocked but only if a passcode is set. Should the passcode be removed, the item will be removed from the keychain.

Data Protection API

When new files are created, they should be protected with the Data Protection API. This will encrypt the file based on a the user's PIN and will grant access to the encrypted file in different scenarios depending on the protection level used.

From most secure to least:

  • NSFileProtectionComplete - Only available when the device is unlocked and 10 seconds after locked.
  • NSFileProtectionCompleteUnlessOpen - Open files can be read/written after the device is locked.
  • NSFileProtectionCompleteUntilFirstUserAuthentication - This is the default and allows files to be read/written after the device is unlocked after a reboot.
  • NSFileProtectionNone - Although still encrypted, encryption keys would be available to an attacker and so provide minimal levels of security.

For sample code, see here.

Android

Screenshots

If this current application screen contains sensitive information, it may be possible for an attacker to view this information in two ways; firstly if the user takes and shares a screenshot (or if the screenshot is recovered by an attacker in another way) and if an attacker can view the screenshot shown by Android in the recent apps menu.

To protect against this, it is possible to disable screenshots of our application by setting the FLAG_SECURE window flag

It should be noted that there are some controls that may still display including:

  • AutoCompleteTextView
  • Spinner (both dropdown and dialog modes)
  • the overflow menu of the framework-supplied action bar
  • ShareActionProvider
  • Dialog and subclasses (e.g., AlertDialog)
  • Toast
  • PopupWindow
  • ListPopupWindow
  • PopupMenu
  • legacy context menus

If sensitive information is displayed in these controls, the following library here is recommended

Although this does provide some protection to a user, it should be acknowledged that a user can find other ways to leak the screen such as more advanced screen grabbing techniques (especially on a rooted device) or by using a camera to take a picture of the screen.

Web Cache

As many apps use web services or embed web controls, it's likely sensitive information will be cachced when using the WebView control. Often, this can include passwords, credit card details, session tokens and more. Care should be taken to make sure caching is disabled or cached data is removed.

The WebView control has a clearCache(boolean includeDiskFiles) method that should be called periodically to make sure nothing sensitive is cached and available to an attacker. In ClearCache(boolean includeDiskFiles), the includeDiskFiles should be true to ensure RAM and files are cleared.

Internal storage

Android provides a SharedPreferences class to store simple key/value pairs and is placed within the application sandbox. Data stored within the sandbox could be available to attackers in the following scenarios:

  • Malware is running as the same permission level as the application.
  • Malware is running with root privileges.
  • Application vulnerability granting access to the application sandbox.
  • Application has been backed up.
  • Files are created with global RW access.

Because of this, it should be assumed that an attacker can access the data and files stored within the sandbox and so nothing sensitive should be stored. If that cannot be achieved, data should be encrypted and the key placed in the Android KeyStore using the KeyStore API. The key should protected with a with a user supplied PIN or passcode.

Code examples can be found here and here.