CHAPTER 2
Android Security

image

Android is a relatively new mobile platform created by Google and the Open Handset Alliance. It is based on a Linux kernel and is typically programmed with the Java language. Android provides a substantial set of abstractions for developers, including ones for user interfaces, application life cycle, various application types, efficient IPC mechanisms, and permissions. The platform also provides key system applications such as the Dialer, Contact Manager, and Home screen, as well as development and debugging tools for integration with Eclipse. All of this is provided on top of a traditional Linux security model, which is still used.

The Android platform claims to be “open,” the meaning of which seems to be largely open to interpretation. Many companies claim their patented or even closed-source software is “open” because they published an API. Android, on the other hand, is open because developers can see and change its source code without restrictive licenses or fees. It is also open because it’s designed to be securable and is able to run third-party applications. Platforms with weaker security models sometimes need to cover up their weakness by locking the applications down to only the “known good” ones, thus throwing up barriers to application development and hindering user choice. The Open Handset Alliance takes the idea of “open” further and even states “Android does not differentiate between the phone’s core applications and third-party applications” (Open Handset Alliance, 2009). This might be true from the perspective of Android, but probably not to a third-party developer trying to change the system settings menu or the Wi-Fi driver on the users’ phones. Android applications are considered “equal,” but more in the sense that you and the Mayor are equal (sure, you each get one vote, but he can do a lot of things you can’t). Android lets anyone build a cell phone distribution with whatever permissions they want for their apps or others’ apps. However, if are using someone else’s Android distribution, they make the rules about which device drivers are installed.

Android distributions can be configured so that their owners do not have root access or can’t change certain aspects of the system or settings. So far this approach is common on phones, and it can help users feel safe if they lose their phone, or install third-party programs. It also helps reassure carriers that licensed content such as ringtones is somewhat protected. Phones can also go through a process of being “locked” to a particular network, which helps protect the business model of carriers who sell devices at a loss to encourage subscriptions. However, with any phone, someone technical with physical access to the device can probably “fix” either of these configurations with a bit of time and effort. Indeed, it is not just security flaws in Android that could subvert such efforts, but the boot loader, radio firmware, memory protection, and bus configuration (both software and physical). An owner breaking root on a their own device shouldn’t harm the security model of Android, however, and sensible people probably expect users to get full control of their phones. Open devices aren’t good at working against their users, although history suggests that neither are closed devices (such as the iPhone).

The future of Android is unclear. It obviously has had great commercial success in its first year, and it has an enormous number of features and an excellent development environment. How it will handle compatibility issues, different form factors, screen sizes, and so on, has yet to be demonstrated, but there is a lot of buzz about new devices. At the time of writing, the only widely deployed device is the T-Mobile G1, and support for paid applications on Google’s Android Market is fairly new.

One of the unique things about the Android platform is that developers have the possibility of directly contributing to its future development. If you have some clever feature or idea for how to make the platform better, you can bundle up a set of patches and submit them for inclusion. This process is similar to how other open-source projects accept community contributions and support.

Development and Debugging on Android

Android has two types of developers: application developers who build software for the platform based on the Android SDK, and system developers who extend or adapt the Android platform for their devices or to contribute back to the platform. Most system developers work for Google or phone manufacturers. Application developers are much more numerous and better supported, and that is the group this chapter is primarily written for.

The documentation for Android includes a lot of introductory material for application developers, including videos about the life cycle of applications, working examples of how to use features, and step-by-step tutorials. The software development kit (SDK) provides free tools for building and debugging applications, supporting developers on Linux, Windows, and OS X. Detailed instructions for configuring the tools on each platform are included. The SDK has a very functional emulator that emulates an ARM-based device similar to the T-Mobile G1, although alternate virtual hardware configurations with Android Virtual Devices are supported as of SDK 1.5. When doing system development (as opposed to application development), you should probably use GNU Linux. OS X is also an option (but Windows really isn’t). Even application developers, and especially those looking to deeply understand the security model of Android, should at least become familiar with the open-source platform used by system developers, which leaves Windows developers at a disadvantage because that system is not open source.

TIP

Microsoft Windows can actually be used to develop applications for Android, but having an Ubuntu virtual machine comes in handy. When working with custom hardware or on system programming when the platform is being recompiled, a linux machine, with its easier adjustment of device drivers and case sensitive file system is necessary. Copying the built source code from a Unix machine onto a Vista machine can make it easier to review, especially with Windows tools like Source Insight (http://sourceinsight.com), which is a handy Windows-only program editor and analyzer that works with mixed development environments well.

Debugging support is built into Android and provided in such a way that working with a device or with the emulator is mostly interchangeable. Android’s support for debugging is provided primarily through a debugging deamon (/sbin/adbd), which allows software on your development machine to connect to the software running on the device. There are two distinct ways to debug on the platform—one for native code and the other for code running in the virtual machine (Dalvik).

Code developed using the SDK generally runs in the Dalvik VM. Much of the system runs in a Dalvik VM, and you can debug this code either while it runs in the emulator or on the device. This is also the “easy code” to debug, and tutorials from Google walk you through it. For the device-based debugging to work, you need to have the Android Debug Bridge Daemon (adbd) running on the device. This is usually started by going into Settings | Applications | Development and then clicking USB debugging on your device. It is on by default on many systems with persist.service.adb.enable = 1 in their SystemProperties (often set in /default.prop). This program runs as the user “shell” and provides data stream forwarding services for TCP and UDP, Unix domain sockets, and more. It also has the ability to execute commands on the device as the “shell” account and can therefore install packages as well as copy files onto or off of the device. Many system files are not readable or writeable by the shell account, so you may need to take additional steps to perform some system alterations depending on what devices you are working with.

To become familiar with Android, before debugging software on it you should play with the Android Debug Bridge (adb), which is the command-line client program that interacts with adbd on the device (or emulator). After connecting some devices to your computer or starting an emulator, you can get a list of the devices available by typing adb devices. In Figure 2-1, you can see that the program adb first starts a daemon on the local machine, which finds the Android devices available on the system and lists them when the devices command is given.

image


Figure 2-1 Android Debug Bridge client use

The list shows three devices (by serial number): an emulator and two physical ones. When more than one device is connected, you specify which you want your command to run against with the –s option for adb. In this case, I have run a shell on the second physical Android device. Once my shell starts, I am able to run the limited set of utilities installed on the device, such as the mount command (see /system/bin for more). The Android security model is much like that of Linux; the UID of a process is critical in what it can or can’t do. The adbd program, which adb uses to facilitate debugging and provide this shell, is not an exception. It allows you to explore the kind of access programs have. You can see that adbd does have a few special rights by running the id command (note the additional groups adbd is a member of):

$ id

uid=2000(shell) gid=2000(shell)
groups=1003(graphics), 1004(input), 1007(log), 1011(adb), 3003(inet)

The commands available in the shell are familiar, although the implementations tend to be limited. Cell phones tend not to have manual pages installed, so in order to figure out how commands work you need to experiment, look online for help, or review their source code. The source code isn’t provided as part of the SDK, but instead is available in a GIT repository for system developers. By looking in system/core/toolbox, you can see the source for the commands. This will help you figure out the syntax you need. My favorite commands are summarized at the end of this chapter.

Android’s Securable IPC Mechanisms

Android implements a few key tools used to communicate with or coordinate between programs securely. These mechanisms give Android applications the ability to run processes in the background, offer services consumed by other applications, safely share relational data, start other programs, and reuse components from other applications safely.

Much of the interprocess communication (IPC) that occurs on Android is done through the passing around of a data structures called Intents. These are collections of information that have a few expected properties the system can use to help figure out where to send an Intent if the developer wasn’t explicit. The Action property expresses what the Intent is for (the Intent.ACTION_VIEW action indicates that the data is to be displayed to the user, for example). The data property is an optional URI and could point to a file, contact, web page, phone number, and so on. Intents also potentially have a collection of key/value pairs called extras, as well as flags, components, and other more advanced features, only some of which we will discuss.

Each of these IPC mechanisms uses Intents in some capacity and is probably somewhat familiar to most Android developers. However, because using these safely is key to Android security, let’s briefly review each mechanism:

Activities

Activities are interactive screens used to communicate with users. A “Hello World” Android application is just an Activity, configured with a resource that says “Hello World.” Intents are used to specify an Activity, and this may be done ambiguously to allow the user to configure their preferred handler.

Broadcasts

Broadcasts provide a way to send messages between applications—for example, alerting listeners to the passage of time, an incoming message, or other data. When sending a broadcast an application puts the message to be sent into an Intent. The application can specify which Broadcasts they care about in terms of the Intents they wish to receive by specifying an IntentFilter.

Services

Services are background processes that toil away quietly in the background. A service might play music; others handle incoming instant messages, file transfers, or e-mail. Services can be started using an Intent.

ContentProviders

ContentProviders provide a way to efficiently share relational data between processes securely. They are based on SQL and should be used carefully. Some of the nice user interface (UI) widgets Android provides make using ContentProviders very tempting, even when data isn’t highly relational. ContentProviders can be secured with Android permissions, and used to share data between processes, like files might be on traditional Unix like systems.

Binder

Binder provides a highly efficient communication mechanism on Android. It is implemented in the kernel, and you can easily build RPC interfaces on top of it using the Android Interface Definition Language (AIDL). Binder is commonly used to bridge Java and native code running in separate processes.

Android’s Security Model

Android is based on the Linux kernel, which provides a security model. Android has abstractions that are unique to it, however, and they are implemented on top of Linux, leveraging Linux user accounts to silo applications. Android permissions are rights given to applications to allow them to take pictures, use the GPS, make phone calls, and so on. When installed, applications are given a unique user identifier (UID); this is the familiar Unix UID seen on desktops and servers. It is a small number like 1011 that is unique on a given system and used by the kernel to control access to files, devices, and other resources. Applications will always run as their given UID on a particular device, just like users always have their same UID on a particular server but different UIDs on unrelated systems. The UID of an application is used to protect its data, and developers need to be explicit about sharing data with other applications. Applications can entertain users with graphics, play music, run native code and launch other programs without needing any permissions.

The need for permissions minimizes the impact of malicious software, unless a user unwisely grants powerful rights to dubious software. Preventing people from making bad but informed choices is beyond the scope of the security model—the permission model is designed to make the choice an informed one. The Android permission model is extensible, and developers need to keep in mind what is reasonable for a phone user to understand when defining new permissions for them. A confused user can’t make good choices. To minimize the extent of abuse possible, permissions are needed for programs that perform potentially dangerous operations that the phone needs to support, such as the following:

image    Directly dialing calls (which may incur tolls)

image    Accessing private data

image    Altering address books, e-mail, and so on

Generally a user’s response to annoying, buggy, or malicious software is simply to uninstall it. If the software is disrupting the phone enough that the user can’t uninstall it, they can reboot the phone (optionally in safe mode, which stops nonsystem code from running) and then remove the software before it has a chance to run again.

Android’s runtime system tracks which permissions each application has; these permissions are granted either when the OS was installed or upon installation of the application by the user. In order to be installed, the application requests that the user approve its permissions. Users will be hesitant to install applications that want access to personal data or the dialer. Most won’t mind giving Internet or coarse location access, or any permission that makes sense for the application being installed.

Android Permissions Review

Applications need approval to perform tasks their owner might object to, such as sending SMS messages, using the camera, or accessing the owner’s contact database. Android uses manifest permissions to track what the user allows applications to do. An application’s permission needs are expressed in its AndroidManifest.xml file, and the user agrees to these upon install.

NOTE

The same install warnings are used for side-loaded and Market applications. Applications installed with adb don’t show warnings, but that mechanism is only used by developers. The future may bring more installers than these three.

When installing new software, users have a chance to think about what they are doing and to decide to trust software based on reviews, the developer’s reputation, and the permissions required. Deciding up front allows them to focus on their goals rather than on security while using applications. Permissions are sometimes called manifest permissions or Android permissions to distinguish them from Linux file permissions. In some rare cases, Android needed to tweak the underlying Linux kernel to support powerful permissions. For example, to support the INTERNET permission, which controls which programs can create network connections, the OS has been altered to require membership to the inet group (typically GID 3003) for certain system calls to work. This isn’t the usual way a Linux system is configured, but it works well. Programs with INTERNET permission are granted membership in the inet group. By enforcing permissions in the OS rather than in the VM or system libraries, Android maintains its security even if the VM is compromised by a hostile application. Writing secure VMs that perform well, use little power, and stop applications from misbehaving (like Sun Microsystem’s Java VM does) is rather hard, and Android’s design avoids needing to do all of this. Breaking out of the Dalvik VM is actually very easy, and documented APIs allow it to be done. However, this doesn’t affect enforcement of Android permissions.

To be useful, permissions must be associated with some goal that a user can understand. For example, an application needs the READ_CONTACTS permission to read the user’s address book (the permission’s full name is “android.permission.READ_CONTACTS”). A contact management program needs READ_CONTACTS permission, but a block stacking game shouldn’t (although if the game vibrates the phone or connects to a high-score Internet server, it might need VIBRATE and INTERNET permission). Because the permission model is simple, it’s possible to secure the use of all the different Android IPC mechanisms with just a single type of permission.

Starting Activities, starting or connecting to Services, accessing ContentProviders, sending and receiving broadcast Intents, and invoking Binder interfaces can all require the same permission. Users only need to understand that their new contact manager needs to read contacts, not what the actual C mechanism used are.

TIP

Users won’t understand how their device works, so keep permissions simple and avoid technical terms such as Binder, Activity, and Intent when describing permissions to users.

Once installed, an application’s permissions can’t be changed. By minimizing the permissions an application uses, you minimize the consequences of potential security flaws in the application and make users feel better about installing it. When installing an application, users see requested permissions in a dialog similar to the one shown in Figure 2-2. (This dialog lists permissions; the installation dialog gives a bit more information and the option to install as well.) Installing software is always a risk, and users will shy away from software they don’t know, especially if it requires a lot of permissions. Make sure you ask for the minimum set of permissions you can get away with.

From a developer’s perspective, permissions are just strings associated with a program and its UID. You can use the Context class’s checkPermission(String permission, int pid, int uid) method to programmatically check whether a process (and the corresponding UID) has a particular permission, such as READ_CONTACTS (note that you would pass the fully qualified value of READ_CONTACTS, which is “android.permission.READ_CONTACTS”). This is just one of many ways permissions are exposed by the runtime to developers. The user view of permissions is simple and consistent; the idiom for enforcement by developers is consistent, too, but adjusts a little for each IPC mechanism.

The following code (AndroidManifest.xml) shows a sample permission definition. Note that the description and label are resources to aid in localizing the application.

<permission
    xmlns:android=“http://schemas.android.com/apk/res/android”
    android:name=“com.isecpartners.android.ACCESS_SHOPPING_LIST”
    android:description=“@string/access_perm_desc”
    android:protectionLevel=“normal”
    android:label=“@string/access_perm_label”>
</permission>

image


Figure 2-2 Dialog showing Application permissions to users. (Chu, 2008.)

Manifest permissions like this one have a few key properties. Two text descriptions are required: a short text label and a longer description used on installation. An icon for the permission can also be provided (but isn’t included in the example). All permissions must also have a name that is globally unique. The name is the identifier used by programmers for the permission and is the first parameter to Context.checkPermission. Permissions also have a protection level (called protectionLevel, as shown in the preceding example).

Table 2-1 shows the four protection levels for permissions. (See http://code.google.com/android/reference/android/R.styleable.html#AndroidManifest-Permission_protectionLevel or search for “Android Manifest Permission protectionLevel” for platform documentation.)

image


Table 2-1 Android Manifest Permission Protection Levels

If you try to use an interface you don’t have permissions for, you will probably receive a SecurityException. You may also see an error message logged indicating which permission you need to enable. If your application enforces permissions, you should consider logging an error on failure so that developers calling your application can more easily diagnose their problems. Sometimes, aside from the lack of anything happening, permission failures are silent. The platform itself neither alerts users when permission checks fail nor allows granting of permissions to applications after installation.

NOTE

Your application might be used by people who don’t speak your language. Be sure to internationalize the label and description properties of any new permission you create. Have someone both technical and fluent in the target languages review them to ensure translations are accurate.

In addition to reading and writing data, permissions can allow applications to call upon system services as well as read or alter sensitive data. With the right permission, a program can cause the phone to dial a number without prompting the user, thus potentially incurring tolls.

Creating New Manifest Permissions

Applications can define their own permissions if they intend other applications to have programmatic access to them. If your application doesn’t intend for other applications to call it, you should just not export any Activities, BroadcastReceivers, Services, or ContentProviders you create and not worry about permissions. Using a manifest permission allows the end user to decide which programs get programmatic access. For example, an application that manages a shopping list application could define a permission named “com.isecpartners.ACCESS_SHOPPING_LIST” (let’s call it ACCESS_SHOPPING_LIST for short). If the application defines an exclusive ShoppingList object, then there is now precisely one instance of ShoppingList, and the ACCESS_SHOPPING_LIST permission is needed to access it. The ACCESS_SHOPPING_LIST permission would be required for callers trying to see or update the shopping list, and users would be warned prior to granting this right to a new application. Done correctly, only the programs that declare they use this permission could access the list, giving the user a chance to either consent or prevent inappropriate access. When defining permissions, keep them clear and simple. Make sure you actually have a service or some data you want to expose, not to just interactive users but to other programs.

Adding permissions should be avoided by using a little cleverness whenever possible. For example, you could define an Activity that adds a new item to the shopping list. When an application calls startActivity and provides an Intent to add a new shopping list item, the Activity could display the data provided and ask for confirmation from the user instead of requiring permission enforcement. This keeps the system simple for users and saves you development effort. A requirement for Activities that immediately alters the list upon starting would make the permission approach necessary.

Creating custom permissions can also help you minimize the permission requirements for applications that use your program programmatically. For example, if an application needs permissions to both send SMS messages and access the user’s location, it could define a new permission such as “SEND_LOCATION_MESSAGE”. (Note that location determination can require multiple permissions, depending on which scheme the particular phone uses.) This permission is all that applications using your service would need, thus making their installation simpler and clearer to the user.

Intents

Intents are an Android-specific mechanism for moving data between Android processes, and they are at the core of much of Android’s IPC. They don’t enforce security policy themselves, but are usually the messenger that crosses the actual system security boundaries. To allow their communication role, Intents can be sent over Binder interfaces (because they implement the Parcelable interface). Almost all Android interprocess communication is actually implemented through Binder, although most of the time this is hidden from us with higher-level abstractions.

Intent Review

Intents are used in a number of ways by Android:

image    To start an Activity (by coordinating with other programs) such as browsing a web page.

Example: Using Context’s startActivity() method.

image    As Broadcasts to inform interested programs of changes or events.

Example: Using Context’s sendBroadcast(), sendStickyBroadcast(), and sendOrderedBroadcast() family of methods.

image    As a way to start, stop, or communicate with background Services.

Example: Using Context’s startService(), stopService(), and bindService() methods.

image    As callbacks to handle events, such as returning results or errors asynchronously with PendingIntents provided by clients to servers through their Binder interfaces.

Intents have a lot of implementation details (indeed, the documentation for just the Intent class is far longer than this chapter). However, the basic idea is that they represent a blob of serialized data that can be moved between programs to get something done. Intents usually have an action (which is a string such as “android.intent.action.VIEW” that identifies some particular goal) and often some data in the form of a URI (an instance of the android.net.Uri class). Intents can have optional attributes such as a list of Categories, an explicit type (independent of what the data’s type is), a component, bit flags, and a set of name/value pairs called “Extras.” Generally, APIs that take Intents can be restricted with manifest permissions. This allows you to create Activities, BroadcastReceivers, ContentProviders, and Services that can only be accessed by applications the user has granted these rights to.

IntentFilters

Depending on how they are sent, Intents may be dispatched by the Android Activity Manager. For example, an Intent can be used to start an Activity by calling Context.startActivity(Intent intent). The Activity to start is found by Android’s Activity Manager by matching the passed-in Intent against the IntentFilters registered for all Activities on the system and looking for the best match. Intents can override the IntentFilter match Activity Manager uses, however. Any “exported” Activity can be started with any Intent values for action, data, category, extras, and so on. (Note that an Activity is automatically exported if it has an IntentFilter specified; it can also be exported explicitly via the android:exported=“true” attribute.) The IntentFilter is not a security boundary from the perspective of an Intent receiver. In the case of starting an Activity, the caller decides what component is started and creates the Intent the receiver then gets. The caller can choose to ask Activity Manager for help with figuring out where the Intent should go, but it doesn’t have to.

Intent recipients such as Activities, Services, and BroadcastReceivers need to handle potentially hostile callers, and an IntentFilter doesn’t filter a malicious Intent. (You can enforce a permission check for anyone trying to start an Activity, however. This is explained in the section “Activities.”) IntentFilters help the system figure out the right handler for a particular Intent, but they don’t constitute an input-filtering or validation system. Because IntentFilters are not a security boundary, they cannot be associated with permissions. Although starting an Activity is the example used to illustrate this, you will see in the following sections that no IPC mechanisms using IntentFilters can rely on them for input validation.

Categories can be added to Intents, making the system more selective about what code an Intent will be handled by. Categories can also be added to IntentFilters to permit Intents to pass, effectively declaring that the filtered object supports the restrictions of the category. This is useful whenever you are sending an Intent whose recipient is determined by Android, such as when starting an Activity or broadcasting an Intent.

TIP

When starting or broadcasting Intents where an IntentFilter is used by the system to determine the recipients, remember to add as many categories as correctly apply to the Intent. Categories often require promises about the safety of dispatching an Intent, thus helping stop the Intent from having unintended consequences.

Adding a category to an Intent restricts what it will be resolved to. For example, an IntentFilter that has the “android.intent.category.BROWSABLE” category indicates that it is safe to be called from the web browser. Carefully consider why Intents would have a category and consider whether you have met the terms of that, usually undocumented, contract before placing a category in an IntentFilter. Future categories could, for example, indicate an Intent is from a remote machine or untrusted source. However, because this category won’t match the IntentFilters we put on our applications today, the system won’t deliver them to our programs. This keeps our applications from behaving unexpectedly when the operating environment changes in the future.

Activities

Activities allow applications to call each other, reusing each other’s features and allowing for replacement or improvement of individual system pieces whenever the user likes. Activities are often run in their own process, running as their own UID, and therefore don’t have access to the caller’s data aside from any data provided in the Intent used to call the Activity. (Note that Activities implemented by the caller’s program may share a process, depending on configuration.)

TIP

The easiest way to make Activities safe is just to confirm any changes or actions clearly with the user. If simply starting your Activity with any possible Intent could result in harm or confusion, you need to require a permission to start it. An Intent received by an Activity is untrusted input and must be carefully and correctly validated.

Activities cannot rely on IntentFilters (the <intent-filter> tag in AndroidManifest.xml) to stop callers from passing them badly configured Intents. Misunderstanding this is a relatively common source of bugs. On the other hand, Activity implementers can rely on permission checks as a security mechanism. Setting the android:permission attribute in an <activity> declaration will prevent programs lacking the specified permission from directly starting that Activity. Specifying a manifest permission that callers must have doesn’t make the system enforce an IntentFilter or clean Intents of unexpected values, so always validate your input.

The following code shows starting an Activity with an Intent. The Activity Manager will likely decide to start the web browser to handle it, because the web browser has an Activity registered with a matching IntentFilter.

Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(Uri.parse (“http://www.isecpartners.com”));
this.startActivity(i);

The following code demonstrates forcing the web browser’s Activity to handle an Intent with action and data settings that aren’t permitted by the IntentFilter:

// The browser’s intent filter isn’t interested in this action
Intent i = new Intent(“Cat-Farm Aardvark Pidgen”);
// The browser’s intent filter isn’t interested in this Uri scheme
i.setData(Uri.parse (“marshmaellow:potatochip?”));
// The browser activity is going to get it anyway!
i.setComponent(new ComponentName(“com.android.browser”,
“com.android.browser.BrowserActivity”));
this.startActivity(i);

If you run this code, you will see that the browser Activity starts. However, the browser is robust, and aside from being started it just ignores this weird Intent.

The following code provides a sample AndroidManifest entry that declares an Activity called “.BlankShoppingList”. This sample Activity clears the current shopping list and gives the user an empty list to start editing. Because clearing is destructive, and happens without user confirmation, this Activity must be restricted to trustworthy callers. The “com.isecpartners.ACCESS_SHOPPING_LIST” permission allows programs to delete or add items to the shopping list, so programs with that permission are already trusted not to wreck the list. The description of that permission also explains to users that granting it gives an applications the ability to read and change shopping lists. We protect this Activity with the following entry:

<activity
    android:name=”.BlankShoppingList”
    android:permission=“com.isecpartners.ACCESS_SHOPPING_LIST”>
    <intent-filter>        <action
            android:name=“com.isecpartners.shopping.CLEAR_LIST” />
    </intent-filter>
</activity>

Activities defined without an IntentFilter or an android:exported attribute are not publicly accessible—that is, other applications can’t start them with Context.startActivity(Intent intent). These Activities are the safest of all, but other applications won’t be able to reuse your application’s Activities.

Developers need to be careful when implementing Activities, but also when starting Activities as well. Avoid putting data into Intents used to start Activities that would be of interest to an attacker. A password-sensitive Binder or message contents would be prime examples of data not to include! For example, malware could register a higher priority IntentFilter and end up getting the user’s sensitive data sent to its Activity instead.

When starting an Activity, if you know the component you intend to have started, you can specify that in the Intent by calling its setComponent() method. This prevents the system from starting some other Activity in response to your Intent. Even in this situation, it is still unsafe to pass sensitive arguments in the Intent (for example, processes with the GET_TASKS permission are able to see ActivityManager.RecentTaskInformation, which includes the baseIntent used to start Activities). You can think of the Intent used to start an Activity as being like the command-line arguments of a program (and these usually shouldn’t include secrets either).

TIP

Don’t put sensitive data into Intents used to start Activities. Callers can’t easily require manifest permissions of the Activities they start, so your data might be exposed.

Broadcasts

Broadcasts provide a way applications and system components can communicate securely and efficiently. The messages are sent as Intents, and the system handles dispatching them, including starting receivers and enforcing permissions.

Receiving Broadcast Intents

Intents can be broadcast to BroadcastReceivers, allowing messaging between applications. By registering a BroadcastReceiver in your application’s AndroidManifest .xml file, you can have your application’s receiver class started and called whenever someone sends a broadcast your application is interested in. Activity Manager uses the IntentFilter’s applications register to figure out which program to use to handle a given broadcast. As we discussed in the sections on IntentFilters and Activity permissions, filters are not a security mechanism and can’t be relied upon by Intent recipients. (IntentFilters can sometimes help Intent sender safety by allowing the sending of an Intent that is qualified by a category. Receivers that don’t meet the category requirements won’t receive it, unless the sender forces delivery by specifying a component. Senders adding categories to narrow deliver therefore shouldn’t specify a component.) As with Activities, a broadcast sender can send a receiver an Intent that would not pass its IntentFilter just by specifying the target receiver component explicitly. (See the examples given for Activities in the “Activities” section. These examples can be applied to broadcasts by using sendBroadcast() rather than startActivity() and adjusting the components appropriately for your test classes.) Receivers must be robust against unexpected Intents or bad data. As always, in secure IPC programming, programs must carefully validate their input.

BroadcastReceivers are registered in AndroidManifest.xml with the <receiver> tag. By default they are not exported. However, you can export them easily by adding an <intent-filter> tag (including an empty one) or by setting the attribute android:exported=“true”. Once exported, receivers can be called by other programs. Like Activities, the Intents that BroadcastReceivers get may not match the IntentFilter they registered. To restrict who can send your receiver an Intent, use the android: permission attribute on the receiver tag to specify a manifest permission. When a permission is specified on a receiver, Activity Manager validates that the sender has the specified permission before delivering the Intent. Permissions are the right way to ensure your receivers only get Intents from appropriate senders, but permissions don’t otherwise affect the properties of the Intent that will be received.

Safely Sending Broadcast Intents

When sending a broadcast, developers include some information or sometimes even a sensitive object such as a Binder. If the data being sent is sensitive, they will need to be careful who it is sent to. The simplest way to protect this while keeping the system dynamic is to require the receiver to have permission. By passing a manifest permission name (receiverPermission is the parameter name) to one of Context’s broadcastIntent() family of methods, you can require recipients to have that permission. This lets you control which applications can receive the Intent. Broadcasts are special in being able to very easily require permissions of recipients; when you need to send sensitive messages, you should use this IPC mechanism.

For example, an SMS application might want to notify other interested applications of an SMS it received by broadcasting an Intent. It can limit the receivers to those applications with the RECEIVE_SMS permission by specifying this as a required permission when sending. If an application sends the contents of an SMS message on to other applications by broadcasting an Intent without asserting that the receiver must have the RECEIVE_SMS permission, then unprivileged applications could register to receive that Intent, thus creating a security hole. Applications can register to receive Intents without any special privileges. Therefore, applications must require that potential receivers have some relevant permission before sending off an Intent containing sensitive data.

TIP

It is easier to secure implementing Activities than BroadcastReceivers because Activities can ask the user before acting. However, it is easier to secure sending a broadcast than starting an Activity because broadcasts can assert a manifest permission the receiver must have.

Sticky Broadcasts

Sticky broadcasts are usually informational and designed to tell other processes some fact about the system state. Sticky broadcasts stay around after they have been sent, and also have a few funny security properties. Applications need a special privilege, BROADCAST_STICKY, to send or remove a sticky Intent. You can’t require a permission when sending sticky broadcasts, so don’t use them for exchanging sensitive information! Also, anyone else with BROADCAST_STICKY can remove a sticky Intent you create, so consider that before trusting them to persist.

TIP

Avoid using sticky broadcasts for sharing sensitive information because they can’t be secured like other broadcasts can.

Services

Services are long-running background processes provided by Android to allow for background tasks such as playing music and running a game server. They can be started with an Intent and optionally communicated with over a Binder interface via a call to Context’s bindService() method. (This is a slight oversimplification, but by using bindService(), you can eventually get a binder channel to talk with a Service.) Services are similar to BroadcastReceivers and Activities in that you can start them independently of their IntentFilters by specifying a Component (if they are exported). Services can also be secured by adding a permission check to their <service> tag in the AndroidManifest.xml. The long-lasting connections provided by bindService() create a fast IPC channel based on a Binder interface (see Binder Interfaces section). Binder interfaces can check permissions on their caller, allowing them to enforce more than one permission at a time or different permissions on different requests. Services therefore provide lots of ways to make sure the caller is trusted, similar to Activities, BroadcastReceivers, and Binder interfaces.

Calling a Service is slightly trickier. This hardly matters for scheduling MP3s to play, but if you need to make sensitive calls into a Service, such as storing passwords or private messages, you’ll need to validate that the Service you’re connect to is the correct one and not some hostile program that shouldn’t have access to the information you provide. (An old attack on many IPC mechanisms is to “name-squat” on the expected IPC channel or name. Attackers listen on a port, name, and so on that trusted programs use to talk. Clients therefore end up talking to the wrong server.) If you know the exact component you are trying to connect to, you can specify that explicitly in the Intent you use to connect. Alternatively, you can verify it against the name provided to your SeviceConnection’s onServiceConnected (ComponentName name, IBinder service) implementation. That isn’t very dynamic, though, and doesn’t let users choose to replace the service provider.

To dynamically allow users to add replacement services and then authorize them by means of checking for the permission they declared and were granted by the user, you can use the component name’s package as a way to validate the permission. The package name is also available to your ServiceConnection’s onServiceConnected(ComponentName name, IBinder binder) method. You receive the name of the implementing component when you receive the onServiceConnected() callback, and this name is associated with the application’s rights. This is perhaps harder to explain than to do, it and comes down to only a single line of code:

res = getPackageManager().checkPermission(permToCheck,
name.getPackageName());

Compare the result of the checkPermission() call shown here with the constants PackageManager.PERMISSION_GRANTED and PackageManager. PERMISSION_DENIED. As documented, the returned value is an integer, not a boolean.

ContentProviders

Android has the ContentProvider mechanism to allow applications to share raw data. This can be implemented to share SQL data, images, sounds, or whatever you like; the interface is obviously designed to be used with a SQL backend, and one is even provided. ContentProviders are implemented by applications to expose their data to the rest of the system. The <provider> tag in the application’s AndroidManifest.xml file registers a provider as available and defines permissions for accessing it.

The Android security documentation mentions that there can be separate read and write permissions for reading and writing on a provider. It states that “holding only the write permission does not mean you can read from a provider” (Google, 2008).

People familiar with SQL will probably realize that it isn’t generally possible to have write-only SQL queries. For example, an updateQuery() or deleteQuery() call results in the generation of a SQL statement in which a where clauses is provided by the caller. This is true even if the caller has only write permission. Controlling a where clause doesn’t directly return data, but the ability to change a statement’s behavior based on the stored data value effectively reveals it. Through watching the side effects of a series of calls with clever where clauses, callers can slowly reconstruct whatever data is stored. As an example of this, attackers exploiting “blind” SQL injection flaws use this technique of repeated queries on for flaws that don’t directly expose query results in order to reconstruct the database of vulnerable systems. You could certainly create a provider for which this is not the case, especially if the provider is file or memory based, but it isn’t likely that this will just work for simple SQL-based providers. Keep this in mind before designing a system that relies on write-only provider access.

Declare the read and write permissions you wish enforced by the system directly in AndroidMainfext.xml’s <provider> tag. These tags are android:readPermission and android:writePermission. These permissions are enforced at access time, subject to the limitations of the implementations discussed earlier. A general permission tag needed for any access can also be required.

TIP

Assume clients with write access to a content provider also have read access. Describe any write permission you create as granting read-write access to SQL-based providers. Consider creating permissions like ACCESS_RESOURCE rather than separate READ_RESOURCE and WRITE_ RESOURCE permissions when dealing with SQL-based providers.

Implementing a provider that is shared with other applications involves accepting some risks. For example, will those other applications properly synchronize their accesses of the data and send the right notifications on changes? ContentProviders are very powerful, but you don’t always need all that power. Consider simpler ways of coordinating data access where convenient.

An advanced feature providers may use is dynamic granting and revoking of access to other programs. The programs granted access are identified by their package name, which is the name they registered with the system on install (in their <manifest> tags, android:package attribute). Packages are granted temporary access to a particular Uniform Resource Identifier (URI). Generally, granting this kind of access doesn’t seem like a great idea, though, because the granting isn’t directly validated by the user and there may not be correct restrictions on the query strings the caller can use. Also, I haven’t worked with this option enough to give advice about using it securely. It can be used by marking your provider tag with the attribute android:grantUriPermissions=“true” and a subsequent <grant-uri-permission> with attributes specifying which URIs are permitted. (You can find the rather weak documentation for this at http://code.google.com/android/reference/android/R.styleable.html#AndroidManifestGrantUriPermission.) Providers may then use the grantUriPermission() and revokeUriPermission() methods to give add and remove permissions dynamically. The right can also be granted with special Intent flags: FLAG_GRANT_READ_URI_PERMISSION and FLAG_GRANT_WRITE_URI_PERMISSION. Code that does this kind of thing would be a great place to start looking for security holes, although the open source Android code did not use this feature as of version 1.5.

Avoiding SQL Injection

To avoid SQL injection requests, you need to clearly delineate between the SQL statement and the data it includes. If data is misconstrued to be part of the SQL statement, the resultant SQL injection can have difficult-to-understand consequences—from harmless bugs that annoy users to serious security holes that expose a user’s data. SQL injection is easily avoided on modern platforms such as Android via parameterized queries that distinguish data from query logic explicitly. The ContentProvider’s query(), update(), and delete()methods and Activity’s managedQuery() method all support parameterization. These methods all take the “String[] selectionArgs” parameter, a set of values that get substituted into the query string in place of “?” characters, in the order the question marks appear. This provides clear separation between the content of the SQL statement in the “selection” parameter and the data being included. If the data in selectionArgs contains characters otherwise meaningful in SQL, the database still won’t be confused. You may also wish to make all your selection strings final in order to avoid accidentally contaminating them with user input that could lead to SQL injection.

SQL injection bugs in data input directly by the end user are likely to annoy users when they input friends whose names contain SQL meta-characters such as the single quote or apostrophe. A SQL injection could occur wherever data is received and then used in a query, which means data from callers of Binder interfaces or data in Intents received from a Broadcast, Service, or Activity invocation, and these would be potential targets for malware to attempt to exploit. Always be careful about SQL injection, but consider more formal reviews of code where data for a query is from remote sources (RSS feeds, web pages, and so on). If you use parameterized types for all values you refer to and never use string concatenation to generate your SQL, you can avoid this class of security issues completely.

Intent Reflection

A common idiom when communicating on Android is to receive a callback via an Intent. For an example of this idiom in use, you could look at the Location Manager, which is an optional service. The Location Manager is a binder interface with the method LocationManager.addProximityAlert(). This method takes a PendingIntent, which lets callers specify how to notify them. Such callbacks can be used any time, but occur especially frequently when engaged in IPC via an Activity, Service, BroadcastReceiver, or Binder interface using Intents. If your program is going to send an Intent when called, you need to avoid letting a caller trick you into sending an Intent that they wouldn’t be allowed to. I call getting someone else to send an Intent for you intent reflection, and preventing it is a key use of the android.app.PendingIntent class, which was introduced in Android SDK 0.9 (prior to which intent reflection was endemic).

If your application exposes an interface allowing its caller to be notified by receiving an Intent, you should probably change it to accept a PendingIntent instead of an Intent. PendingIntents are sent as the process that created them. The server making the callback can be assured that what it sends will be treated as coming from the caller and not from itself. This shifts the risk from the service to the caller. The caller now needs to trust the service with the ability to send this Intent as itself, which shouldn’t be hard because they control the Intent’s properties. The PendingIntent documentation wisely recommends locking the PendingIntent to the particular component it was designed to send the callback to with setComponent(). This controls the Intent’s dispatching.

Files and Preferences

Unix-style file permissions are present in Android for file systems that are formatted to support them, such as the root file system. Each application has its own area on the file system that it owns, almost like programs have a home directory to go along with their user IDs. An Activity or Service’s Context object gives access to this directory with the getFilesDir(), getDir(), openFileOutput(), openFileInput(), and getFileStreamPath() methods, but the files and paths returned by the context are not special and can be used with other file-management objects such as FileInputStream. The mode parameter is used to create a file with a given set of file permissions (corresponding to the Unix file permissions). You can bitwise-OR these permissions together. For example, a mode of MODE_WORLD_WRITABLE | MODE_WORLD_READABLE makes a file world-readable and writable. (World is also known as “other,” so MODE_WORLD_WRITEABLE creates other writeable files, like the command chmod o+w somefile does.) The value MODE_PRIVATE cannot be combined this way because it is just a zero. Somewhat oddly, the mode parameter also indicates if the resultant file is truncated or opened for appending with MODE_APPEND.

The following code is a simple example of creating a sample file that can be read by anyone:

fos = openFileOutput(“PublicKey”, Context.MODE_WORLD_READABLE);

The resultant FileOutputStream (called “fos” in this example) can be written to only by this process, but it can be read by any program on the system.

This interface of passing in flags that indicate whether files are world-readable or world-writable is simpler than the file permissions Linux supports, but should be sufficient for most applications. To experiment with full Linux file permissions, you could try executing chmod, or the “less documented” android.os.FileUtils class’s static method setPermissions(), which takes a filename and a mode uid and gid. Generally, any code that creates data that is world-accessible must be carefully reviewed to consider the following:

image    Is anything written to this file sensitive? For example, something only you know because of a permission you have.

image    Could a change to this data cause something unpleasant or unexpected to happen?

image    Is the data in a complex format whose native parser might have exploitable vulnerabilities? Historically a lot of complex file format parsers written in C or C++ have had exploitable parser bugs.

image    If the file is world-writeable, a bad program could fill up the phone’s memory and your application would get the blame! This kind of antisocial behavior might happen—and because the file is stored under your application’s home directory, the user might choose to fix the problem by uninstalling your program or wiping its data.

Obviously, executable code such as scripts, libraries, and configuration files that specify which components, sites, or folders to use would be bad candidates for allowing writes. Log files, databases, and pending work would be bad candidates for world-readability.

SharedPreferences is a system feature that is backed by a file with permissions like any others. The mode parameter for getSharedPreferences(String name, int mode) uses the same file modes defined by Context. It is very unlikely you have preferences so unimportant you don’t mind if other programs change them. I recommend avoiding using MODE_WORLD_WRITEABLE and suggest searching for it when reviewing an application as an obvious place to start looking for weaknesses.

Mass Storage

Android devices are likely to have a limited amount of memory on the internal file system. Some devices may support larger add-on file systems mounted on memory cards, however. For example, the emulator supports this with the –sdcard parameter, and it is referenced repeatedly in Android’s documentation. Storing data on these file systems is a little tricky. To make it easy for users to move data back and forth between cameras, computers, and Android, the format of these cards is VFAT, which is an old standard that doesn’t support the access controls of Linux. Therefore, data stored here is unprotected and can be accessed by any program on the device.

You should inform users that bulk storage is shared with all the programs on their device, and discourage them from putting really sensitive data there. If you need to store confidential data, you can encrypt it and store the tiny little key in the application’s file area and the big cipher-text on the shared memory card. As long as the user doesn’t want to use the storage card to move the data onto another system, this should work. You may need to provide some mechanism to decrypt the data and communicate the key to the user if they wish to use the memory card to move confidential data between systems.

NOTE

A tiny 128-bit key is actually very strong. You can probably generate it at random because users will never need to see it. But think about the implications for backups before trying this.

Binder Interfaces

Binder is a kernel device driver that uses Linux’s shared memory feature to achieve efficient, secure IPC. System services are published as Binder interfaces and the AIDL (Android Interface Definition Language) is used not just to define system interfaces, but to allow developers to create their own Binder clients and servers. The terminology can be confusing, but servers generally subclass android.os.Binder and implement the onTransact() method, whereas clients receive a Binder interface as an android.os.IBinder reference and call its transact() method. Both transact() and onTransact() use instances of android.os.Parcel to exchange data efficiently (the native implementation of this Parcel formats data as it is expected by the kernel mode Binder device). Android’s support for Binder includes the interface Parcelable. Parcelable objects can be moved between processes through a Binder.

Under the covers, a Binder reference is a descriptor maintained by the Binder device (which is a kernel mode device driver). Binder IPC can be used to pass and return primitive types, Parcelable objects, file descriptors (which also allows memory maps), and Binders. Having a reference to a Binder interface allows calls to its interface—that is, you can call transact() and have a corresponding call to onTransact() occur on the server side—but this does not guarantee that the service exposing the interface will do what the caller requests. For example, any program can get a reference to the Zygote system service’s Binder and call the method on it to launch an application as some other user, but Zygote will ignore such requests from unauthorized processes.

Binder security has two key ways it can enforce security: by checking the caller’s identity and via Binder reference security.

Security by Caller Permission or Identity Checking

When a Binder interface is called, the identity of the caller is securely provided by the kernel. Android associates the calling application’s identity with the thread on which the request is handled (the application’s UID and its process’s current PID are provided). This allows the recipient to use their Context’s checkCallingPermission(String permission) or checkCallingPermissionOrSelf (String permission) method to validate the caller’s rights. Applications commonly want to enforce permissions they don’t have on callers; therefore, checkCallingPermissionOrSelf(String permission) allows the application to still call itself even if it lacks the normally needed permission. Binder services are free to make other binder calls, but these calls always occur with the service’s own identity (UID and PID) and not the identity of the caller.

Binder services also have access to the caller’s identity using the getCallingUid() and getCallingPid() static methods of the Binder class. These methods return the UID and process identifier (PID) of the process that made the Binder call. The identity information is securely communicated to the implementer of a Binder interface by the kernel. This is similar to how Unix domain sockets can tell you the identity of the caller, or most IPC mechanisms in Win32.

A Binder interface can be implemented a number of ways. The simplest is to use the AIDL compiler to create a Stub class, which you then subclass. Inside the implementations of the methods, the caller is automatically associated with the current thread, so calling Binder.getCallingUid() identifies the caller. Developers who direct requests to handlers or implement their own onTransact() (and forego AIDL) must realize that the identity of the caller is bound to the thread the call was received on and therefore must be determined before switching to a new thread to handle a request. A call to Binder.clearCallingIdentity() will also stop getCallingUid() and getCallingPid() from identifying the caller. Context’s checkPermission(String permission, int pid, int uid) method is useful for performing permission checks, even after the caller’s identity has been cleared by using stored UID and PID values.

Binder Reference Security

Binder references can be moved across a Binder interface. The Parcel.writeStrongBinder() and Parcel.readStrongBinder() methods allow this and provide some security assurances. When reading a Binder reference from a Parcel with readStrongBinder(), the receiver is assured (by the kernel’s Binder driver) that the writer of that Binder had a reference to the received Binder reference. This prevents callers from tricking servers by sending guesses of the numerical value used in the server’s process to represent a Binder the caller doesn’t have.

Getting a reference to a Binder isn’t always possible. (By Binder, I mean a reference to a Binder interface. In Java, this is represented by an android.os.Binder object.) Because servers can tell if callers had a particular Binder, not giving out references to a Binder can effectively be used as a security boundary. Although Zygote might not protect its Binder interfaces from exposure, many Binder objects are kept private. To use reference security, processes need to carefully limit the revealing of Binder objects. Once a process receives a Binder, it can do whatever it likes with it, passing it to others or calling its transact() method.

Binders are globally unique, which means if you create one, nobody else can create one that appears equal to it. A Binder doesn’t need to expose an interface—it might just serve as a unique value. A Binder can be passed between cooperating processes. A service could provide callers a Binder that acts as a key, knowing that only those who receive the key (or had it sent to them) can later send it back. This acts like an unguessable, easily generated password. The Activity Manager uses the reference nature of Binders to control the management of Surfaces and Activities.

Android Security Tools

Following is a list of mobile application security tools for the Android OS. All of these tools were authored by Jesse Burns and can be found here at http://www.isecpartners.com/mobile_application_tools.html.

Manifest Explorer

Both Android distributions, and every application installed on them must have an AndroidManifest.xml policy file, which Manifest Explorer helps the user find and view. The AndroidManifest.xml sets critical application policy which is explained at http://developer.android.com/guide/topics/manifest/manifest-intro.html. The file is of great interesting when analyzing system security because it defines the permissions the system and applications enforce and many of the particular protections being enforced. The Manifest Explorer tool can be used to review the AndroidManifest.xml file, the security policies and permissions of applications and the system, as well as many of the IPC channels that applications define and which end up defining the attack surface of applications. This attack surface outline is a common starting point for understanding the security of application and Android distributions.

The tool is simple to use. As shown in Figure 2-3, the tool lists all the system’s applications, allows the user to select one, and then displays the contents of the AndroidManifest.xml file that pertain to the selected application. The Android system policy can be found under the special case package name “Android”. A menu option enables saving the extracted manifest, so the testers can read it more comfortably on a PC for manual inspection.

image


Figure 2-3 Manifest Explorer main screen

Package Play

Package Play shows the user all installed packages on the mobile device, and some of the interesting features those packages install. This helps the user in the following ways:

image    Provides an easy way to start and explore exported Activities

image    Shows defined and used permissions

image    Shows activities, services, receivers, providers, and instrumentation as well as their export and permission status

image    Switches to Manifest Explorer or the Setting’s applications view of the application

Figure 2-4 shows a screenshot of Package Play. The first step with Package Play is to select the package to examine. By reviewing the list, the user may see software they did not originally install (such as software preloaded by the hardware manufacturer) that is not included in the open-source Android OS.

image


Figure 2-4 Package Play

Intent Sniffer

On Android, an Intents are one of the most common ways applications communicate with each other. The Intent Sniffer tool performs monitoring of runtime routed broadcasts Intents, sent between applications on the system. It does not see explicit broadcast Intents, but defaults to (mostly) unprivileged broadcasts. There is an option to see recent tasks’ Intents (GET_TASKS), as the Intent’s used to start Activities are accessible to applications with GET_TASKS permission like Intent Sniffer. The tool can also dynamically update the Actions and Categories it scans for Intents based on using reflection and dynamic inspection of the installed applications. Figure 2-5 shows a screenshot of Intent Sniffer.

Intent Fuzzer

A fuzzer is a testing tool that sends unexpected or incorrect input to an application in an attempt to cause it to fail. Intent Fuzzer is exactly what is seems—it is a fuzzer for Intents. It often finds bugs that cause the system to crash as well as performance issues on devices, applications or custom platform distributions. The tool can fuzz either a single component or all installed components. It works well on BroadcastReceivers but offers less coverage for Services, which often use Binder interfaces more intensively than Intents for IPC. Only single Activities can be fuzzed, not all them at once.

image


Figure 2-5 Intent Sniffer

image


Figure 2-6 Intent Fuzzer

Instrumentations can also be started using this interface, and although ContentProviders are listed, they are not an Intent-based IPC mechanism and so cannot be fuzzed with this tool. Developers ma want to adapt Intent Fuzzer so that it can provide Intents more appropriate for their application. Figure 2-6 shows a screenshot of Intent Fuzzer.

Conclusion

Android is a great platform for writing secure applications. It provides a type-safe language (Java), an advanced security model, a proven class library, and a powerful set of appropriate and securable abstractions for development on mobile devices. Android’s framework typically defaults to safe behavior unless the developer explicitly decides to share data between applications, and then it focuses the security model around the user. Android’s open design means that finding and fixing security holes is done by the widest possible group of people—not just a few insiders who might be biased about how important a problem is in something key to the company they work for and whose stock they have options on.

Trying to keep owners of devices from gaining root access predictably hasn’t worked out very well on Android, or even on competing closed platforms. Fortunately, this isn’t a security requirement for the platform and therefore shouldn’t affect user security as long as users are able to patch the vulnerabilities that would allow malicious applications to elevate to root. If you find yourself thinking that you can seize control of any general-purpose device from its owner, there is probably a serious flaw in your reasoning. The most you can probably do is protect data so that if a device is lost, encrypted data can’t be recovered.

Android isn’t perfect—it uses a lot of open-source components, some of which have a spotty record. Linux and WebKit both have needed numerous security fixes in the last year, but this isn’t a problem for application developers as much as for those who choose to create an Android distribution for their devices. Users may even come to appreciate the honesty and rapidity of these fixes, and the security people feel from avoiding scrutiny with closed-source code might be an illusion. Many mobile platforms on the market today have little in the way of patching, which leaves consumers vulnerable to security flaws for years that condition is unlikely to be allowed to persist any longer.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.222.109.4