Chapter    20

Android Security and Permissions

The fact that you are reading this book, and are thinking of developing applications for Android, means you have certainly been exposed to ongoing security issues that are an inescapable fact of modern operating systems and programs. Catchy names like Heartbleed and Shellshock have brought security to the forefront of even nontechnical consumers’ thinking, so people looking to buy and use your applications will be more aware than ever that there are risks and problems that can lurk in an unexpected corner of the Internet, or the latest Android game they just downloaded.

The good news is that security is a fundamental part of all phases of development, deployment, and use of applications in Android, and there are lots of things Android does for you and many tools at your disposal to help you build robust, secure applications. In this chapter we explore the permissions system that allows you to safely share resources and interact with other parts of Android; we discuss the packaging and deployment of applications to a device; and we cover the protection offered by Android’s package management, package signing, and related Google Play Store mechanisms. Let’s get started!

Requesting Permissions for Your Application

You are already familiar with a few instances of requesting permissions for the example applications used earlier in the book. In Chapter 13, the PhoneCallExample application needed the CALL_PHONE permission in order to directly dial a number; and in Chapter 17, the example applications working to write data to storage needed the WRITE_EXTERNAL_STORAGE permission in order to change files.

These are just two examples of the dozens of permissions baked into Android with the goal of protecting sensitive data or powerful (and potentially costly) features. In addition to using the Android-provided set of permissions, you as a developer are also able to create custom permissions for your application, and you have control over whether and how other applications use your resources. I cover custom permissions more later in the chapter.

You need to request each permission you wish to be granted through a <uses-permission> element in your AndroidManifest.xml file. You may remember seeing these entries in the earlier examples, but now, so you get the complete picture, let me explain that you can have as few or as many permission requests as you deem fit in your manifest; each is a child element under the <manifest> root that takes this form:

<uses-permission android:name="<the permission name>"
   android:maxSdkVersion="<version number>"

When you are specifying the value for the android:name attribute, you have well over 100 separate permissions from which to choose. I won’t waste pages repeating them all here, so to get an idea of your choices, you can check the full list in the Android developer documentation at http://developer.android.com/guide/topics/manifest/uses-permission-element.html. A few of the notable and interesting permissions that I haven’t already covered in earlier chapters are as follows:

  • ACCESS_FINE_LOCATION: Enables your application to get the maximum precision for device location from a range of sensors including GPS, wifi, cell tower triangulation, and more.
  • BODY_SENSORS: Gain access to data about the device user’s physical body, taken from sensors, such as skin temperature monitors, pulse monitors, pedometers, and so on.
  • FLASHLIGHT: Allows access to camera flashes and dedicated flashlights that can be used as light sources and works (separate from any other function, like taking pictures).
  • INTERNET: Talks to remote network IPs and services running remotely onthe device.

Any Android-provided permission lives in the android.permission namespace, so when you are specifying any permission value in the android:name attribute of <uses-permission>, you need to include the fully-qualified name, such as android.permission.INTERNET.

The android:maxSdkVersion attribute tells Android the threshold for version-checking when you are installing and running your application. A device that is running an Android release higher than the maxSdkVersion you specify ignores the permission request. The main use for this attribute is not to inadvertently fail permission checks and break your application; instead, it primarily works with known permission relaxation changes that happen in Android from release to release. For instance, from API version 19 on, an application no longer needs to request WRITE_EXTERNAL_STORAGE to write to its own application-scoped directories. In fact, we could add this to our example application from Chapter 17 and save the file system permission checks on newer API releases.

Listing 20-1 shows an excerpt of the AndroidManifest.xml file for the PermissionsExample application from the ch19/PermissionsExample folder. You can see it is as simple as directly editing the XML to add the desired permission entries.

For those nostalgic users who are fans of Eclipse and the ADT, there is a graphical XML editor that helps ensure that layouts, manifests, and other XML files are always valid and well-formed. For the AndroidManifest.xml and permissions in particular, this editor also provides a list of known platform-provided permissions from which you can just click to insert the selected permissions into the underlying manifest file. Figure 20-1 shows the editor in action.

9781430246862_Fig20-01.jpg

Figure 20-1. The graphical XML editor in Eclipse provides plenty of help specifying permissions

This might seem like needless UI gloss, but for Eclipse users, it ensures that permission typographical naming errors are avoided; you will find this functionality very useful once you understand the design-time limitations in debugging permissions (more on that later in the chapter). For Android Studio users, Google dispensed with a graphical editor for manifest files and instead relies on the content assistance feature to provide valid permission entries as you type. That strictly is just as good at getting permission names right, but it is an overall loss in ensuring that your XML file as a whole is valid and well-formed from the beginning.

Dealing with Debugging Permissions

When you are working with permissions for secured services and resources, one of the frustrations of Android development is the lack of design-time checks for required permissions as you write your Java code. This means that in the absence of any other tools or tricks, you typically first learn of any mistakes or omissions to required permissions when you are debugging on an emulated device.

In general, you see errors emitted in LogCat that describe the symptoms of what has gone wrong, and usually some suggestive steps indicate what permission your application is trying to use but currently lacks. This differs depending on the specifics of what you are trying to do, but as an example, if you attempt to use an Internet-based resource without the android.permission.INTERNET permission in your manifest, typically an error like this appears:

java.net.SocketException: Permission denied (maybe missing INTERNET permission)

Many of the permissions return a more generic SecurityException, but you get the idea.

Installing Applications and Accepting Permissions

Android’s approach to bundling permissions and presenting them to the user for acceptance has historically been a fairly basic, even crude, approach. There have even been a few comical slip-ups as Google has moved to meet user demand that it provide much more control over runtime permission use, which has been a mainstay for other mobile platforms such as iOS.

Pre-Marshmallow Behavior

The vast majority of devices running in the wild are using Android versions 2.x, 3.x, or 4.x; all of these versions, with one minor exception, require the potential user of your application to accept all of your permission requests when they go to install, or else they abort any attempt to install. There is no halfway point, no optional permissions, and nothing as nuanced as the approach seen in other systems.

There are some subtle and not-so-subtle impacts of this approach. First and foremost, users are forced to make potentially important decisions about sharing data, such as contacts or location, all at once, and for an application that might request dozens of permissions, this can present a bewildering choice to the user.

A related issue is the users’ perception, in general, of what the application may do with the permission they grant, and what it can do with multiple permissions they grant in combination. Great examples are what happens when the same application requests android.permission.CAMERA and android.permission.INTERNET. This makes sense for a Snapchat-style picture messaging system, but imagine this combination of requests from something like a streaming music app. Similarly, android.permission.CONTACTS and android.permission.CALL_PHONE makes sense for a phone book app, but what if an alarm clock application asked for that? Users are sensitive to combinations that they perceive as exposing their personal data and risking their privacy, and they are even more sensitive when the request combinations seem to bear no relation to the way expect to use the application.

As a developer, your best approach for all Android versions, but pre-Marshmallow Android 6.0 in particular, is to request as few permissions as possible. When you do request a permission, provide a clear rationale for why your application needs a given permission, and expect to lose a small set of potential users who might not be prepared to accept what you ask for.

APP OPS, OR APP OOPS?

Enduring criticism of the all-or-nothing approach to application permissions seemed to precipitate a change at Google with the Android 4.3 release, which included an intriguing new feature called App Ops. This was a permission management approach that allowed users to selectively revoke permissions after they installed applications, which gave the user the control many believed they rightful needed and deserved.

This was in keeping with Google’s general “Put the User First” principle, but sadly, it seemed to clash with competing commercial and other objectives. Shortly after the release of Android 4.3, the 4.4.2 “update” was released; it reached out and hid all App Ops functionality from the end user. All the framework support was left in place, but as a functional user-controlled fine-grained permission system, App Ops disappeared as quickly as it appeared.

As a developer, even if you decide to detect release levels all the way down to minor point releases, I don’t recommend coding specific behavior for the presence of App Ops on an Android 4.3 or 4.4 platform. Google eventually released App Ops in the guise of runtime permissions in Marshmallow.

Marshmallow and Beyond

With the release of Android 6.0 Marshmallow, Google has changed tack and has finally given users what they have long asked for in the form of selective permission granting when they install an application. This changed behavior is still very new, since Marshmallow is coming to market as this book goes to print.

What this means for you as a developer is that in addition to adhering to the principle of least privilege, meaning that you only ask for the permissions you strictly need, you should also prepare for how your application will behave if it is denied the expected permission to perform some action—write to a file, read contacts, take a picture, and so on. In such a situation, it’s likely that your application’s default behavior is that Android simply silently fails, and the next piece of code in your application then also fails with some form of unhandled exception, such as a null reference, because your expected resource isn’t there when you ask for it.

Applications using the new permission model for Android Marshmallow trigger a system prompt to the user when they attempt to use a given permission, and Android triggers the new onRequestPermissionsResult() callback in your application so that you can perform your permission allowed/denied logic.

Google is gradually preparing for the full release of Android Marshmallow, but at this time, the final (third) preview is still ironing out issues in the new runtime security model. The behavior only changes if your application requests permissions using the special <uses-permission-sdk-m> value for the preview releases of Marshmallow in addition to checking the device’s build of Android via Build.VERSION.CODENAME.

In the full release, users will also be able to revoke permissions they granted at installation time. This means that just because your application works initially, you can’t take it for granted that it will always have the permissions it had when it was first installed. Android now supports the checkSelfPermission() method from any context, which allows you to test for granted permissions before you attempt to use them. This method takes the permission name as the parameter—for example:

Context.checkSelfPermission(Manifest.permission.CALL_PHONE);

Make sure you watch out for updates to forward and backward compatibility as Google irons out the bugs on the https://developer.android.com/preview/features/runtime-permissions.html page of the Android developer website.

Trading In Permissions

Android adds and even removes permissions from the platform over time. As you saw in Chapter 17, when we discussed file access, Google has flagged that it will introduce the READ_EXTERNAL_FILE permission at some future point. WRITE_EXTERNAL_STORAGE was introduced in Android 1.5, but its implementation was altered in Android 4.3, when the security model of Android changed to always allow an application to write to its own private-named file locations.

Implicit permissions are also bundled with your application automatically, depending on your setting for the android:minSdkVersion attribute in <uses-sdk> in your manifest. An SDK setting of 3 implicitly adds android.permission.READ_PHONE_STATE and android.permission.WRITE_EXTERNAL_STORAGE, even if your application doesn’t care for, and doesn’t use, those permissions. Your application users see these implicit permission requests, along with your explicit ones, at install time. When you change to a higher SDK version, these permissions are no longer implicitly requested, but others might be. You shouldn’t rely on the implicit permissions for your application if you actually do need them. Instead, always explicitly add them to your manifest so that if Google does swap out the implicitly requested permission in some future SDK version, your application still requests what it needs and keeps working.

The release of Android Marshmallow introduces 11 new permissions, which you can read about in depth in the Android developer documentation. A few of the more notable new appearances are as follows:

  • GET_ACCOUNTS_PRIVILEGED: Provides access to the set of all registered accounts on the device.
  • PACKAGE_USAGE_STATS: Allows access to the metrics on how often components of a package, such as one of your activities or services, are called.
  • USE_FINGERPRINT: Accesses the fingerprint scanner hardware on devices when it is present.

Creating Custom Permissions

You are not limited to the set of permissions Android provides with each release of the API. If you find yourself creating data, activities, services, content providers, or other assets over which you’d like to exert some control, then you can secure them with custom permissions you define.

Most often, you will want to consider custom security permissions if your application is storing and using sensitive or private user data. At the context level, you can also secure the content provider and other code you provide that supplies the logic to manipulate and use such data.

Using custom permissions is a two-part process. First, you declare the existence of the permission, and then you enforce its use.

Declaring Custom Permissions

To declare the permission you would like to create, add a <permission> element to your manifest. The <permission> element has eight attributes, of which you need to provide at least the following:

  • android:name: This string will be the programmatic name of the permission, referred to in code and XML elements. By convention, use your package name and a meaningful permission name to create the fully-qualified name. This prevents name collisions across namespaces.
  • android:label: This will be the permission name displayed to users at install time and at runtime in Android 6.0 and later. Being short and meaningful are key characteristics of a good label.
  • android:description: This string provides some meaningful narrative to what your permission does. “Protects FoozApp” isn’t a great description. “The FoozKey permission protects your personal player profile in the FoozApp game” is better.

Note  You must define the android:description attribute as a resource reference to a string, such as android:description="@string/my_desc". There is no literal text in the attribute within your manifest for this one.

We can expand the manifest I showed earlier in Listing 20-1 by adding a custom permission declaration, as shown in Listing 20-2.

You can also define a banner and an icon to use when prompting users and include your permission in Android’s permission groups and levels as with the stock Android permission grouping approach.

Enforcing Custom Permissions

With your permission defined, you can then opt to enforce it to restrict access through either declarations in your manifest, or through code in the related Java classes.

You can protect an activity, receiver, or content provider by adding the android:permission attribute to the relevant context element in your manifest. For instance, to protect our PermissionsExampleActivity from the example application, we would further extend the manifest, as shown in Listing 20-3.

With this permission in place, no other application can invoke our PermissionsExampleActivity through a startActivity() call without first requesting the PE_SEE_HIDDEN permission. If this is a service (which I cover in the next chapter), it can’t be implicitly started, stopped, or bound in another context without the permission. If we modify the code and manifest to be a broadcast receiver, we ignore any intent designed to trigger invocation unless the intent initiator holds the PE_SEE_HIDDEN permission.

To achieve the same effect in code is a little harder, because the methods available are fairly primitive. You can check the permissions of the caller by using the checkCallingPermissions() method with a permission name to see if the caller holds that permission. You can also telegraph your permission requirements when sending broadcasts in your code via the sendBroadcast() method by using the optional permission name parameter to signal to receivers that you only want responses from those that hold the named permission.

Securing Applications for Publication and Execution

There is a great deal more to the security and protection mechanisms provided by Android than just the permission system. Two areas in particular where the security framework shows its mettle are in the signing requirements that guarantee and protect the provenance of a given application through the use of PKI and certificates, and in Android’s Linux underpinnings, which means application process and user contexts enjoy strict boundaries and protection. We’ll explore both of the aspects of Android security next.

Securing Your Application with Certificate Signing

Before you can publish your application to Google Play and make it available for download and installation to Android devices, you are required to sign you application with a suitable X.509-style PKI certificate. For those of you not familiar with PKI and digital certificates, PKI is a cryptographic system you can use to do things like assert identity, establish trust, and pass secrets. You can find many great descriptions online.

With you digital certificate in hand (or more accurately, on your machine), you can sign the .apk file that, in effect, is the zip-formatted container that holds you application code, manifest, resources, and assets, all ready for deployment.

Sourcing or Creating a Signing Certificate

Obviously to sign an .apk file with a digital certificate you actually need the certificate. You have two broad options: making a commercial purchase of a certificate issued from a publicly trusted root or intermediate Registry, or generating a self-signed certificate using a tool such as keytool.

With self-signed certificates, your main concern is that, by definition, no other party asserts the validity and trustworthiness of your signing certificate. For this reason, self-signed certificates are considered the poor cousins of the PKI world.

The Keystore

Whichever style of certificate you choose, you will likely want to use the keystore facility that keytool offers to manage your certificates and public/private key material.

You can tell keytool to store a (self-signed) certificate it is generating by passing the –keystore parameter and the path you would like to use as your keystore. A bunch of other parameters are offered by keystore; you can examine these at your leisure by reviewing the output of keytool --help.

Whether you realized it or not, you have already been using a certificate and a keystore when you have been working with the example applications from the book. Both Eclipse with the ADT and Android Studio automatically create a developer keystore known as the Debug Keystore, and both also create a self-signed certificate you use when deploying the .apk files from the example applications to a device emulator. You can examine this debug setup, and even change it so it uses a different keystore location and/or certificate by opening the Build options from the Android > Build menu. There are some “gotchas” to doing this, however, so keep reading to be sure you understand the implications.

Signing Your APK

With a certificate in place, and your build system (Eclipse, Android, Ant, or something else) capable of building your .apk file, you have multiple options in how you approach signing.

You can use the jarsigner tool that ships with the JDK to manually sign your .apk file, which needs a few relevant parameters to do its job.

jarsigner -keystore <path to your keystore> <necessary passwords> <path to your .apk> <application name>

The pseudo-parameters shown here give you the basics, and obviously, more options are available for the jarsigner tool. The drawback is the finicky nature of using a command-line tool and the risk of exposing passwords when you are running command-line tools in general.

Android Studio users can generate the signed .apk directly from the project view by choosing the Build image Generate Signed APK menu option. You are prompted for exactly the same information the jarsigner tool requires, just through a friendlier UI that helps avoid some of the mistakes. It should not surprise you to know that the information is used to actually run jarsigner itself under the hood.

With a signed .apk file, you can manually deploy your application through the “side loading” technique using the adb tool, or you can publish it to your developer account on Google Play for public download and use. Deploying with adb can be as simple as this:

adb install <path to signed .apk file>

You can entertain other options and considerations for deployment, such as optimizing the final .apk file using the zipalign tool. You can read more about this in the Android developer documentation.

Signing Is (Almost) Forever, So Take Care

You know already that you must sign your application with your chosen certificate before you can installed it on a device, and that Google helps this process with your emulator environments by automatically creating debug certificates and keystores. If you have an Android Developer account and plan to publish applications to Google Play, the certificate takes on additional importance.

The signing certificate along with the fully qualified package name for your application form the principal identifiers for your application. When you create updates in the future, either because you are adding features or fixing bugs, you need to sign the new-and-improved application with the same certificate in order for Google Play to consider it an upgrade for the same application, rather than a separate application in its own right.

This might seem onerous, but it’s one of the most important guarantees user have that an update to their favorite application comes from you, and not someone impersonating you. For this reason, as well as for the general security imperatives of protecting yourself and your users, you should take a great deal of care with the key material for your certificate. Protect your private key and the keystore repository you are using, keep an offline backup, and do not upload this to any form of cloud service or repository. Should you ever lose your key material and be unable to use your existing certificate, there is no feasible way to re-create it. If you are forced to use a different certificate for signing updates to your applications, those applications will be considered completely separate applications by Android and Google Play.

The certificates you use for signing your application also need to be unusually long-lived. By default, the certificates you create with keytool are valid for around 20 years (14,000 days). You can opt to use a shorter or longer validity period, but Google Play checks to ensure a lifetime is valid to at least the 22nd of October, 2033. This is very different from certificates used for SSL, S/MIME, or other protocols, where generally shorter-lived certificates are preferred, and rotation to new certificates is performed regularly. You have probably guessed that because of the identification implications, certificate rotation is not practiced with Android applications and their signing certificates.

Protecting Android and Applications at Runtime

In addition to the certificate signing that attests to the authenticity and origin of your application and the permissions model that protects data and services, Android also uses its Linux underpinnings to enforce a runtime process and user model to provide even more security for your application and all the other applications that run on a given device. You can think of this as protecting applications from each other and Android itself from applications.

Every application loaded on to a device or emulator is automatically allocated its own user context and underlying user account. You as a developer do not control this, and the user of the device typically does not know this is happening. Your application runs under the ownership of this account for its entire lifetime on the device, so once its account is allocated at install time, that is a permanent attribute of the application.

Because each application uses its own user account, as with any Linux-based system where many applications are running, the processes are owned by many different users. Figure 20-2 depicts the user and process boundaries for Android applications on a device.

9781430246862_Fig20-02.jpg

Figure 20-2. Imagining the user and process model of Android’s Linux underpinnings

If this is transparent to you as a developer, and to the user running the applications, you might ask why this is important. The main benefit here is that you application’s implicit user account has permissions over files and process artifacts for your application, but not for any other applications. If there is any kind of security vulnerability and one application starts misbehaving, this ownership separation provides another line of defense by ensuring the compromised application cannot automatically run rampant with the files and other resources of other applications at the Linux level.

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

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