I recently had the opportunity to work with an exceptional group of engineers deploying Android on a new device. One of their biggest concerns was security of the platform. The reason? Their device has specific requirements for the protection of data and platform integrity. They had some great concerns (and attack techniques) regarding platform as well as app security, which many vendors do not consider. Often, vendors are in such a rush to get product to market, security is glossed over. In this multi-part series I’m going to cover Android security options for Apps, SDK vendors and platforms.
Android Security Foundation: The App Sandbox
Android’s app model provides developers with a rich set of features and a relatively secure environment, particularly for simple apps. Every app under Android is “sandboxed” into its own process and filesystem space. Taking advantage of the Linux kernel’s process space protection mechanisms, Android assigns each installed app a unique user ID. Unlike traditional desktop operating systems (Linux, Windows, Mac, etc.), Android (generally speaking) uses the concept of the user ID to represent an app rather than a human user. This allows the kernel to keep apps confined in memory, restrict access to underlying hardware or services, and restrict access to the filesystem on the device. By default, each app’s data and resources are contained in a location which only the app and the core framework can access. This design is central to the Android security model.
More advanced apps are becoming commonplace, these apps communicate with each other or with devices/servers via networks. Let’s take a look at some basic security items for your apps which you may be omitting.
At the highest level, Android apps are made up of one or more of four basic components: Activity, Service, ContentProvider or BroadcastReceiver. These are building blocks which apps use to provide their functionality. With the exception of the ContentProvider, the components are activated by Intents,which are special messages sent within the system. Your app’s manifest tells the system what components are present in your app and what Intents they handle via an IntentFilter. Intents can also be explicitly directed at a component if you know its name, no filter required. If you are unfamiliar with Intents and IntentFilters, see the SDK documentation for more details.
Intents are very pervasive in Android: its how apps trigger other apps. They are also used to communicate with other components within the same app. This means that if you are not careful, your app components could receive an Intent from an unknown source. The upshot is the Intent could contain malformed data intended to make your app misbehave, crash or give up information. Take, for example, if you have several activities, but only the top Activity should be triggered by an external source. You would not want another app to start your second or third Activity directly. By default, Android keeps the components in your manifest private,; until, that is, you associate an IntentFilter with it. Even if your Intent payload (action, category, etc.) is custom, if it is in the manifest then your component is no longer private. The solution? Use the
android:exported="false" attribute in your component declaration within your manifest. This overrides the system’s setting, even when an
<intent-filter> tag is present for the component.
Leaving Debug Enabled
Android’s default toolchains do a great job of automatically marking an app as debuggable during development. This allows it to be deployed on an emulator or real device, and allow the developer to attach a debugger. This is done by enabling the
android:debuggable attribute in the
<application> tag within the package’s manifest. This allows the Java side debugger to be attached to your app when it is running. Eclipse and Android Studio do this for you behind the scenes, until you export your build for release. So most developers are not aware this is happening. But, this also means it is possible for you to manually insert this tag into your AndroidManifest.xml file and accidentally ship with it. Sound far fetched? It’s not. I’ve seen multiple apps, some from larger commercial companies, which are available in the Google Play store and have debugging enabled.
So what’s the big deal? Simple: access to the app internals. If you allow a debugger to be attached to your app, the app’s memory, flow and internal structure can be examined and possibly exploited. With a debugger attached, network connection details, username/password details, and other data can be examined. This is a nice lead in to the next topic: securing your data.
Storing Data in Cleartext
Whether or not your app ships with debugging enabled, you need to take precautions against data compromises. Storing usernames and passwords in cleartext (or at all!) is a bad idea. Sounds obvious, right? Someone should have told the iOS Starbucks app author that: it was recently discovered user credentials were stored in the clear. While this was on iOS, the concept is the same and on Android arguably worse since users have a much better chance of “rooting” the device.
Android provides multiple mechanisms for storing data: files, SharedPreference, SQLite databases, ContentProviders, etc. Each of these is backed by something on the filesystem of the device. In some cases (files, SharedPreferences), you could write them to storage which is not protected by the app sandbox. How? Easy: write them to SD card, or external storage. There is a reason external storage access in Android requires a special permission in your app’s manifest. SD cards and USB disks are formatted with FAT32 as opposed to a unix-like filesystem, which is what the internal storage on your Android device uses. FAT32 does not have full user and group based permission support. The kernel’s ability to protect your app’s data from access by an app with another user ID is does not exist. Similarly, ContentProviders are intended to by used to expose data to other apps. If you write sensitive data to your backing store of the ContentProvider but do not protect the provider itself, you open yourself up to attack. On top of all of that, devices can be rooted relatively easily. Once an attacker has root access, they can access all files, databases, etc. on the device.
The solution? Encrypt your app’s sensitive data whether in files or SQLite databases. There are numerous crypto capabilities available in Android or from third parties, such as SQLCipher.
Android Security, like on other platforms, is a complex topic which must be carefully considered. By keeping security in mind and adhering to these simple steps you can keep your app and its data better protected. In the next installment, we’ll look at Android’s permissions architecture and how to leverage it to better secure your app.
i think we can not give android:debuggable=false or true tag in manifest file .eclipse will manage it.
The newer versions of Eclipse and Android Studio do a better job of managing this. However, it is still possible to accidentally override this manually. I’ve seen production apps ship with this turned on, so it is still a valid warning.