Chapter 12

Security

WHAT’S IN THIS CHAPTER?

  • Understanding the OS-level security features in Android
  • Discussing tools for using Android securely
  • Writing secure applications
  • Protecting data and communication
  • Protecting application IP

WROX.COM CODE DOWNLOADS FOR THIS CHAPTER

Please note that all the code examples in this chapter are available at https://github.com/wileyenterpriseandroid/Examples.git and as a part of the book’s code download at www.wrox.com on the Download Code tab.

Mobile devices present one of the most profitable hacking targets in the average person’s digital world. They contain copious amounts of personal information, often include access to bank and retirement accounts, contain all your contacts, and can access your e-mail. They can also fall, without a sound, out of your pocket. They know where you are, can see your face, and can eavesdrop on your conversations while they sit in your backpack. They might also randomly load malicious code from the phones of other people as they walk nearby in the street. Clearly, the stakes in securing mobile applications are high.

Hacking for profit or espionage has become big business worldwide. Keeping user data safe and developer assets secure requires vigilance on the part of mobile developers and handset owners. This chapter covers Android techniques for enhancing security for both handset users and application developers regarding the following topics:

  • Android platform security
  • User techniques for keeping phones secure
  • Writing secure applications that protect privacy and prevent theft
  • Protecting applications from piracy

PLATFORM SECURITY

The previous paragraphs painted a potentially bleak picture of mobile security, but of course those scenarios depend on circumventing Android platform security controls. Mobile device features are generally safe as long as malware does not subvert formidable operating system and application protections.

When confronting long-standing security problems, recent mobile operating systems employ defenses that are leaps and bounds better than security techniques used in traditional desktop platforms like Windows and Mac OS. One of the most common ways to get a desktop virus is to unwittingly open a malicious e-mail attachment. Another pitfall is to allow insecure plugins to run in your web browser — desktop Java Technology from Oracle has recently encountered a string of serious and high-profile security flaws related to Java running in web pages. For years, Windows would run all programs downloaded from the Internet or even from floppy disks with administrative privileges. Once activated a virus could access sensitive system resources at will. Windows XP corrected this problem with user and file system permissions, but many users still ran all programs as an administrative user, thus nullifying the security enhancements. Linux and Mac OSX have always run user-level processes with a vastly reduced level of access — without admin access.

Android takes OS-level protection a step further, by extending the security model already found on Linux and Mac OS to drastically increase the level of isolation between individual applications. Each application runs as an entirely different UNIX user. This simple but effective step uses the base operating system to prevent applications from tampering with each other’s data in the file system, from accessing shared pipes, and a range of Linux resources.

Android also supports application permissions that provide another level of security not found on a platform level in traditional operating systems. Users don’t need to fully trust application code; instead, they can rely on OS-imposed limitations to prevent apps from performing sensitive operations, such as covertly slurping a user’s contacts list out of a device.

In spite of these improvements, modern mobile attacks take many forms. For example, there was a recent spate of hijacked, Trojan applications posing as popular Android applications, such as “Angry Birds”, which caused phones to participate in a spam botnet. The hijacked phones sent out prolific messages at the expense of the end user. Despite enhanced platform security, downloading malicious code onto a device is still a primary concern.


NOTE For reference, the Google Open Source project provides a comprehensive overview of the Android platform and its security model:

KEEPING HANDSETS SAFE

Before you begin writing secure code for Android applications, it’s important to be aware of the tools that end users can use to keep their handsets safe and to know which of these tools help developers write secure applications. Before walking through a set of Android security examples, the chapter covers techniques for safe usage of Android by end users. This involves a discussion of several security tools from Google and other vendors, all of which impact the security of the Android ecosystem.

Avoiding Malicious Applications

For several years, the iPhone was king of the mobile application space. As of the time of writing of this book, Android had caught up significantly and was closing in on 800,000 applications listed in the Google Play store. With that many applications, simple probability gives hackers many chances to sneak code onto user’s phones.

Attacks on Android systems have several common sources:

  • Android applications
  • Browser-based JavaScript
  • Messaging
  • NFC and Bluetooth
  • Kernel root exploits

Secure usage is currently the first defense against these types of attacks. We want to take a look at platform and ecosystem tools that can help handset users keep their phones safe.

Use a Safe Browser Like Google Chrome

If your Android device does not have the Chrome browser pre-installed, you should install it. It’s available in the Google Play store. Many attacks against applications involve cooperation on the part of the browser — like an app that directs the browser to malicious websites. Chrome helps to close holes of this nature with built-in malware and phishing protection and — of critical importance — process-level sandboxing support. Chrome is widely regarded to be one of the most, if not the most, secure browser.

Understand Google Bouncer

To protect users from application threats, Google created the Bouncer program, which is an application that emulates applications to look for malware patterns. The program prevents malicious applicants from gaining entrance to the Google Play application store. Users and developers don’t need to do anything specific to take advantage of Bouncer’s protection — apps are rejected on store submission if they don’t pass security tests when running on the Bouncer emulator.

Beware Installing from Unknown Locations

Although the Google Play store and the Amazon app store provide the “front door” for application installation on Android devices, Android also supports application installation through SD card side loading, as well as the ability to install applications from unknown locations. As many Android developers know, you can get to this location using the following:

Settings -> Applications -> Check Allow "Unknown Sources"

On Android 4.0 or greater use:

Settings -> Security -> Check "Unknown Sources"

Of course, users should keep in mind that although there may be good reasons to download Android applications from unknown sources, careless downloading of applications not fully known to the user is a great way to compromise phone security. For example, one spam botnet attack, that Lookout Security gave the moniker SpamSoldier, spread itself by sending SMS messages with a link for unsuspecting users to download — not particularly sophisticated, but successful against teenagers and other newbies using phones.

Use the Application Verifier Service

Although you might think you know an application from an “unknown source” well enough to install it outside of the store, it’s smart to check it for viruses just in case. As of Android 4.1/4.2, Jellybean, on Google Nexus, Google has provided users with an additional security check that blocks malicious apps from installation, called the application verifier service. The feature is active by default, but users can turn it off, at their own risk, with:

Settings -> Security -> Verify Apps

When you install a new app — from any app store, or “unknown sources”, not just Google Play — the verifier service will collect information about the application. If the Google cloud has information that the application is malicious, it will take one of two actions. If the app is dangerous, Android will not install it. If the app is potentially dangerous, it will warn the user and provide the option of not installing it. You can find instructions for turning on the verifier service for the Google Nexus below:

https://support.google.com/nexus/galaxy/answer/2812853?hl=en-CA

Consider the Success of Security Measures

Now that you have some awareness of major security measures that Google has put in place for Android, it’s time to take a look at publicly available security reviews of them:

Bouncer

Security researchers initially investigated Google Bouncer and found that it was possible to “fingerprint” the service, which meant that it was possible, at one point in time, for applications under review to investigate the Bouncer environment and report back this useful information about it to potentially malicious authors. You can find more information about the review here:

http://blog.trendmicro.com/trendlabs-security-intelligence/a-look-at-google-bouncer/

Such transparency might open the door to security attacks.

Nexus Application Verifier Service

As of November 2012, another security researcher investigated the Nexus Application Verifier Service and presented his results online, along with a description of the App Verifier tool:

http://www.cs.ncsu.edu/faculty/jiang/appverify/

This researcher, a founder of the Android Malware Genome project, attempted to install a large number of known malicious Android applications. Alarmingly, the researcher found a low detection rate of < 20 percent. The results of this research indicate that even with Google’s security measures, users should approach the installation of Android applications with a strong sense of caution. Still, keep in mind that this work was very early in the life of the verifier service, and Google is likely to improve it.

Although Google and other vendors have made considerable progress in protecting user security, these results indicate that device users should know enough about the applications and their corresponding developers to self-curate the apps that they install on their phones. According to sources online, detection rates for malicious apps are well below 100 percent — users should not operate under the assumption that all applications in Android app stores are safe.

Use Google Apps Device Management

Users who have Google Apps for Business accounts can take advantage of additional Android Security features, such as requiring a screen lock and pin or password for users, and remote wipe for lost or stolen phones. Users also get the ability to remotely:

  • Reset pins
  • Ring devices
  • Lock devices
  • Locate devices

After you have a Google Apps for Business account, you also need to download the Device Policy application. You can get this application, like any other, from the Google Play store. Once you have installed it, if you are not signed into your Google Apps account, you will need to add the account to the Device Policy application. Google has provided instructions for installing the Device Policy app:

http://support.google.com/a/users/bin/answer.py?hl=en&answer=2364439

Once the Device Policy is installed, you can set up the device management features:

http://support.google.com/a/users/bin/answer.py?hl=en&answer=1235372&topic=2365092&ctx=topic

Know Alternative Security Products

Beyond tools from Google, the rising need for Android security has bred an industry in advanced mobile application security protection. Some of the more successful companies in this space include Lookout, Appthority, and Bit9. The main features of many of these applications include:

  • Real-time scanning for malware
  • Locating lost devices
  • Remote locking or wiping of handsets to protect security
  • Securely backing up user data such as contacts and password management

Pay Attention to Your Phone Bill

According to Lookout Security, the most prevalent form of Android malware takes the form of toll fraud, which is a covert and particularly common way of sneaking charges into a subscriber’s cell phone bill — 72 percent of Lookout-detected malware involved toll fraud. Typically, toll fraud involves billable SMS messages, which is a common way of paying for mobile transactions. Cell phones have supported text-based billing for many years to enable users to buy ring tones, images, and so on.

An example of toll fraud involves the installation of a malicious app that can hide and respond to billable SMS messages. Such an application will work with a cooperating backend that can receive malicious SMS messages sent from the app. The carrier ends up allowing a charge from the malicious service, since the malicious app is able to receive SMS confirmation messages. The carrier interprets access to a device as confirmation of a user’s identity. With an insidious twist, the toll fraud application will hide the confirmation SMS message so that the handset user never even sees it. The only way that users will ever know that theft has occurred is by paying careful attention to their cell phone bills. For more information, check out the following:

http://bits.blogs.nytimes.com/2012/12/13/lookout-toll-fraud/

Understand Malware Mechanics: The Malware Genome

Another promising Android security investigation called the “malware genome” analyzed known Android exploits to discover their modes of operation and the security flaws in Android and applications that they exploit. A brief summary of the findings concerning malware includes:

  • 86 percent are repackaged legitimate applications.
  • 40 percent used root-level exploits.
  • 90 percent turn phones into botnets — device networks that serve a malicious purpose. A typical botnet might recruit hacked devices to send out SMS spam.
  • 45 percent have built-in support for sending SMS messages, premium rate calls, or making calls without the user knowing.
  • 51 percent are harvesting user information, including user accounts and short messages stored on phones.

To give you an idea of what’s involved in detecting malicious apps, here’s a list of the prominent types of attacks:

  • Repacking — Downloading a legitimate application, unpacking the contents, inserting malicious code, and repacking the app to appear as the original app.
  • Drive by downloads — Downloading malicious content, as by an e-mail attachment, where the user either does not know the payload is downloaded, or is unaware that the download could infect their systems.
  • Update attacks — Initial applications have no malicious code, but an application update includes one. This strategy avoids virus scan detection on first download.
  • Root exploits — Involve memory overruns that give malicious code complete system access. After execution, the main defense against this type of attack is application-based encryption. Unfortunately, Android root exploits often persist in devices because the kernel vulnerabilities they use go unpatched as carriers take time to push OS updates to devices.

NOTE You can learn more about the malware genome here:
You find the comprehensive review of malware applications in the following document:

WRITING SECURE APPLICATIONS

Compared to traditional desktop systems, Android certainly has improved OS-level protection, but mobile software supports complex and detailed data about its users and faces increasingly sophisticated attacks trying to access that lucrative information. Developers writing applications for Android need to consider security upfront and be sure that they write secure code from the first deployment of their application. It’s time to shift focus from keeping malicious code off Android to defending your own application in an environment where malicious code might be present.


NOTE As you learn about writing secure applications, you will encounter several chapter examples that you can invoke from the user interface of the AndroidSecurity project. Import each project into Eclipse, as in previous chapters, run the main apk, and then invoke each one as you read its section in the chapter. Keep in mind that you will have to modify some of the code as you go, and refer to $CODE/AndroidSecurity/README for the most up to date instructions.

Hacking Targets

When it makes its way onto a device, malware seeks access to the system as a whole or to individually installed applications, including the ones you develop. To defend your application, consider these high-value targets that hackers are likely to attack:

  • Security keys — Provide access to encrypted files, which would normally protect even a “rooted” or jail-broken device.
  • Passwords: Passwords provide access to remote web service data, and should not be stored directly on a device.
  • Insecure APIs — Applications that implement Android APIs by creating content providers, using Android Interface Definition Language (AIDL), services, or handling intents should take care to filter out malicious invocations by detecting attack parameters.
  • Permission-based privileges — Unauthorized and transitive use of permissions, also known as “privilege escalation.”
  • Communication channels — AIDL, intents, and services all have the potential to leak sensitive information across process boundaries. Effectively sandboxed applications will leverage modes of communication to access privileges available to your application.
  • Root-level access — If an attacker physically holds a device, it’s fairly easy for them to unlock it and obtain admin access. More often, inadvertently installed malware will take advantage of vulnerabilities in the base of the operating system itself to gain full system access.
  • Billable events — Most malicious app developers are in the business of making money, which means they seek monetary targets like in-app billing or premium SMS messages.

Before getting too paranoid about the number of possible security holes, keep in mind that most Android settings — including file permissions — have secure default values. Android also protects applications using the Linux file system, process model, and a strong security sandbox. Android employs the following technologies to avoid traditional penetrations due to memory: SLR, NX, ProPolice, safe_iop, OpenBSD dlmalloc, OpenBSD calloc, and Linux mmap_min_addr. Android also has interesting security tricks up its sleeve, like the ability to encrypt an entire file system volume and more described in the following location:

http://developer.android.com/training/articles/security-tips.html

Ingredients of a Secure Application

The first step in designing any secure application is to consider the principle of least privilege, which means that applications request only the minimum access to sensitive resources and privileges required for an app to perform its functions. For example, if you’ve written a content provider that needs to be used only in its declaring apk, don’t export the provider to other processes. Instead use android:exported="false". If external applications do need to read from the content provider, allow only read access, instead of requiring read/write access by default. If you are writing a location-aware application that does not need incredibly precise location information, request ACCESS_COARSE_LOCATION instead of ACCESS_FINE_LOCATION. And so on...

Android app developers have important reasons for writing applications that request only the permissions they need:

  • If a hacker compromises your application’s security, either through a published API like a received intent, or any other security backdoor, the privileges granted to your application can become accessible to the attacker. When your app asks only for privileges it needs, it closes unnecessary security risks even in the event of a successful attack. If you “over-privilege” your app, you might leak privileges you did not even need.
  • Users who read the list of permissions your app declares in its manifest are more likely to install apps with smaller sets of less sensitive permissions.

NOTE In Android 2.2, Google released a transitive security bug when its power control widget enabled unauthorized modification of system settings:

Keep the principle of least privilege in mind, as you read the rest of the chapter, which covers the “ingredients” of a secure application that successfully defend against security attacks. These ingredients include:

  • Secure use of permissions
  • Protecting and encrypting data
  • Protecting communication
  • Preventing piracy

Secure Use of Permissions

As you discovered when writing your first Android application, you must declare permissions for features, such as Internet access, used in a given application. Applications use these declarations to request the use of permissions from the user installing an application. Explicitly asking end users to grant all permissions used in an app has some associated controversy. On one hand, a careful user has the opportunity to pick up on strange access requests (such as a to-do list application that asks permission to send SMS messages and to manage Android accounts). On the other hand, perhaps the majority of handset users will not have the technical savvy to know why some permissions might be sensitive, and might get tired of trying to review information they do not understand. On the whole, requiring apps to be open with the capabilities they require will almost certainly lead to informed scrutiny from some portion of each application’s user base.

When writing Android applications that handle sensitive data, it’s important to understand the power of the Android permission system: It’s a fine-grained and powerful capability-granting framework. The Android permission system provides another strong example of how the Android platform has improved security over traditional operating systems — applications for the same user don’t automatically get access to each other’s resources or capabilities. Android enforces strong separation between all running processes.


NOTE As an aside, it’s important not to confuse the Android permission system with the Linux Security model and permissions. In Android, file system permissions are Linux permissions.

Permissions are likely the most prominent of Android security features that app developers need to consider when developing applications. Developers should keep a vigilant eye on which privileges they request, and how they make them available to other applications. This section provides an overview of how permissions work and includes interesting details of important permissions, including a sense of their comparative danger. This section also shows you when and how to create your own custom permissions.

Permission Basics

To review, a permission on Android protects calls that can perform security sensitive operations like sending an SMS message. Permissions can also protect calls that application developers deem sensitive. If a caller invokes a method but does not have the requisite permission, an instance of java.lang.SecurityException will be thrown, preventing the call from taking place. Applications request use of permissions in their AndroidManifest, as follows:

<uses-permission android:name="android.permission.INTERNET" />

Upon installation, end users review the list of permissions an app has requested and can reject the app if they deem the list suspicious.

Android Permissions

The base Android operating system provides a wide array of permissions that protect the functions available on Android devices. You can find them all listed in the class android.Manifest.permission, as follows:

http://developer.android.com/reference/android/Manifest.permission.html

Every Android permission, including custom application permissions, has an associated protection level that gives users and developers a sense of how concerned they should be about granting and asking to use the permission. For example, the permission android.permission.BRICK clearly poses a lot of danger to a device, and is considered a “Dangerous” permission. A declaration of a permission in an AndroidManifest file includes specification of a protection level, as follows:

android:protectionLevel =
    "normal" | "dangerous" |  "signature" | "signatureOrSystem"

The following table explains protection levels in detail:

PROTECTION LEVEL DESCRIPTION
Normal Minimal level threat that does not pose significant danger to the user or the system. Automatically granted on app installation.
Dangerous Poses significant threat to the system and to user data. Dangerous permissions require user approval and are generally subject to a large community of users who will spot suspicious permission requests.
Signature A permission that Android grants only to applications that have the same signature as the app that defined the permission. Automatically granted on signature match.
SignatureOrSystem Reserved for system use; your application should not use this level.

But what practical knowledge do these levels provide? As you can see, Android end users must manually approve all dangerous permissions in your applications, and you should be aware of the ones that will raise eyebrows so you can work to avoid them. Of critical importance are the permissions users don’t want to see when they install your application; you need to convince users that it is okay to download your application.


NOTE This chapter contains more “real-world” knowledge than readers might expect. The intent of the discussion is to show how exploits subvert Android permissions and how users and developers can understand security attacks to avoid becoming malware victims.

High Risk Permissions (Users Might Not Want to Grant)

Many of the permissions that should set off red flags for savvy Android users relate to the hacking targets that we have outlined in this chapter. Access to billable events, private data, sensitive user information, and security keys all have significant potential for exploitation. Here are some comments from the malware genome to give you a sense of the priorities of malware applications:

  • INTERNET, READ_PHONE_STATE, ACCESS_NETWORK_STATE, and WRITE_EXTERNAL_STORAGE permissions are widely requested in both malicious and benign apps.
  • Malicious apps are 10 times more likely to request CHANGE_WIFI_STATE than benign applications, likely because the permission enables hot plug events that are needed for root exploits.
  • Malicious apps clearly tend to request SMS-related permissions — READ_SMS, WRITE_SMS, RECEIVE_SMS, and SEND_SMS — more frequently than benign applications.

Users should install only well known apps, like Google Voice, from trusted vendors like Google that seem to have a very good reason for accessing particularly lucrative target permissions like CALL_PHONE and CALL_PRIVILEGED or the ability access text messages. If a puzzle game requires access to send text messages, it may not be a good idea to download and install it.

The following table lists the top Android permissions requested in malware applications (as provided by the Malware Genome Project) and notes vulnerabilities of each of them.

PERMISSION NAME ACCESS NOTES
INTERNET INTERNET permission is useful to attackers in myriad different ways; here are a few popular ones:
1. Allows an application to open Internet sockets to any outgoing host; contrast to web-based JavaScript which can read responses from connections to its host of origin, excluding HTML5 Cross-Origin Resource Sharing (CORS), which can be as permissive as Android INTERNET permission.
2. Enables a botnet to communicate with its command and control (C&C) server.
3. A common hack directs browser and apps that have INTERNET permission to load malicious website URLs — more on this in the section, “Checking the Caller’s Permissions” later in the chapter.
4. Surprisingly, Android does not require permission to access a user’s photos. Any app that has INTERNET permission can upload user photos to the site of their choice on the Internet: http://bits.blogs.nytimes.com/2012/03/01/android-photos/
READ_PHONE_STATE Provides read-only access to phone state.
ACCESS_NETWORK_STATE Allows applications to access information about networks.
WRITE_EXTERNAL_STORAGE Provides the ability to write to the SD card. Example use: to hide the location of a C&C server.
ACCESS_WIFI_STATE Allows access to information about WiFi networks. Potentially related to root-level exploits.
READ_SMS Allows applications to read existing SMS messages that are for other applications; a nice way to get at text sensitive information.
RECEIVE_BOOT_COMPLETED Requested five times more frequently by malware than legitimate applications.
WRITE_SMS Allows an application to write SMS messages.
SEND_SMS Allows an application to send an outgoing SMS, as would have been required by SpamSoldier. Receiving an SMS is a chargeable event, which makes it an attractive target to thieves. Sending SMS messages is especially attractive given the prevalence of toll fraud schemes based on carrier premium SMS messages.
RECEIVE_SMS Allows applications to receive SMS messages as required for an SMS based push notification system. Receiving an SMS is a chargeable event, which makes the action attractive to thieves.
VIBRATE Allows an application to turn on the phone’s vibrator.
ACCESS_COARSE_LOCATION Provides access to the phone’s coarse or network location — the location value that does not come from the GPS radio.
READ_CONTACTS Provides access to a user’s contacts; clearly valuable information for a hacker.
ACCESS_FINE_LOCATION Provides access to fine-grained GPS information; higher resolution than coarse network location.
WAKE_LOCK Prevents the phone from sleeping or the screen from dimming. This plays into the strategy of malicious applications using the phone for botnets that need the ability to run in the background without the user’s knowledge.
CALL_PHONE Enables outbound calls potentially to premium phone services, likely outside the United States, which can be associated with significant per instance charges.
CHANGE_WIFI_STATE The ability to change WiFi state is related to system events that enable a malicious application to execute root-level exploits.
WRITE_CONTACTS The ability to add contacts is useful for malicious apps in a number of ways — for example, to write a contact that looks like someone they recognize, but perhaps representing a malicious phone number.
WRITE_APN_SETTINGS Allows applications to write the GSM Access Point Name (APN) settings.
RESTART_PACKAGES The permission is deprecated, and applications should not use it.

Using Application-Defined Permissions

Protecting sensitive resources in your own applications, specifically to protect IPC access to your Android components such as content providers or services, may require the use of application-defined permissions. The manifest declaration in Listing 12-1 creates a permission for reading contacts from the contacts’ content provider.

LISTING 12-1: Create a custom permission for accessing contacts

<permission 
    android:name="com.enterpriseandroid.permission.READ_CONTACTS"
    android:label="Read contact information."
    android:description=
        "Enables reading contacts from the contacts content provider."
    android:protectionLevel="dangerous"
    android:permissionGroup="android.permission-group.PERSONAL_INFO"
/>
  • name — The name of the permission that apps will declare in their manifest.
  • label — The label of the permission.
  • description — A description of the permission shown to end users.
  • protectionLevel — The protection level of the permission, as discussed previously. This permission is dangerous, so the user will have to approve it.
  • permissionGroup — The string that defines the group in which the permission will be placed when presented to the end user for permission approval. In this case, the permission relates to personal information.

Enacting the newly defined permission requires checking the required permission when sensitive code is called, as in Listing 12-2.

LISTING 12-2: Checking an application-defined permission

PackageManager manager = getPackageManager();
int hasPermission =
    manager.checkPermission(
        "com.enterpriseandroid.permission.READ_CONTACTS",
        "com.enterpriseandroid.androidSecurity");
        
if (hasPermission != PackageManager.PERMISSION_GRANTED) {      
    throw new SecurityException("Permission Denied: Reading Contacts.");
}

This snippet of code resides in an application method that needs to read enterpriseandroid contacts. To be secure, the method should verify that a caller also has permission to read this sensitive information by comparing the return value of checkPermission to PERMISSION_GRANTED. If either the calling code or the method code do not have permission, then the method should fail by throwing the security exception.

Protecting Data

As this book has discussed, typical places to store data include files in the file system (both internal flash storage and external SD card devices), SQLite databases, and content providers. Different Android components and files systems require different handling to maintain security. The next several sections cover securing Android file systems and application components.

Securing Data in Files

Android extends the Linux security system and protects files using the base Linux file system. In Linux, file permissions follow a standard format based on binary settings, where individual bits represent whether a given file is readable, writeable, or executable by the file owner, the file group, or by all users. As an example, a file with permissions, (7, 5, 5) or (111, 110, 110) would be readable, writeable, and executable by the owner, and readable and executable by everyone else.

Android relies on the core Java API, specifically java.io.File, to enable programmatic control over file system permissions. The following methods on File change underlying Linux file permissions:

setReadable(boolean readable, boolean ownerOnly)
setWriteable(boolean writeable, boolean ownerOnly)

The following sequence of invocations:

File myFile = new File(...);
myFile.setReadable(true, false);
myFile.setWriteable(true, false);

results in a Linux permission setting of (110,000,000) or (600), which is a secure access setting that allows only the application to read and write a file stored in an application’s internal storage.

Internal Storage

Android internal storage supports Linux file system permissions. Applications writing files to their data directory, located at /data/data/<manifest_package_name>, can make use of Linux file permissions as described in the previous section. Trolling for inadvertently accessible files is a popular technique for malware to gain access to sensitive data. In almost all cases, applications should create files that are readable and writeable only by the application itself. Keep the following in mind when setting file permissions:

  • World accessible files should be carefully reviewed for sensitive data.
  • World writeable files can be filled up with junk to overwrite system memory for denial attacks.

Data on Upgrade

As you learned when deploying your first Android application, all applications that deploy to the Google Play store must have a digital signature. These signatures fulfill several roles for Android applications and the Android platform. In many cases, they prevent malicious applications from pretending to be better known and legitimate applications. They also prevent masquerading applications from “upgrading” in place over the presence of existing applications that may have already written data. For example, if a banking application wrote data into files on Android internal storage, Android does not permit a malicious application claiming to be an upgrade for the legitimate application to access the files.

External Storage

External storage devices on Android, such as removable SD cards, don’t support Linux file system permissions for the simple reason that the file system format of most SD cards is a legacy format initially created for DOS, called FAT, which does not support permissions on individual files. Storing sensitive information in files on external storage is usually not a good idea since they can only have world readable permissions and will persist even after the writing application is uninstalled from the device. If you do need to store information on the SD card, it’s a good idea to protect it using encryption.

Encrypting Data

Even if a file resides in internal storage with proper file system permissions, it’s still a good idea to encrypt its data. File system permissions will not protect bank accounts, passwords, and other information when thieves steal and jail-break phones. It’s fairly straightforward to encrypt data using the Android API, but it definitely helps to have basic knowledge of encryption to decide which algorithms you should use to secure data in files, and in RESTful calls (covered a bit later in this chapter).

The field of computer cryptography has a long and diverse history, going as far back as ciphers used by the Roman military and code breaking machines used during World War II. Encryption is the process of applying a mathematical algorithm to data to yield output data that is unintelligible to anyone who does not have a valid decrypting key. If you have this key, you can produce the original data by applying a decrypting algorithm to the encrypted data.

Symmetric and Asymmetric Cryptography

Modern encryption algorithms typically take symmetric or asymmetric forms:

  • A symmetric encryption algorithm means that you use the same key to encrypt and decrypt data.
  • Asymmetric encryption, also known as public key cryptography, involves the use of two different keys — the public key (the encrypting key) and a private key (the decrypting key). Usually, the public, private key pair is created by an entity known as a certificate authority (CA). See Figure 12-1.

You can find symmetric and asymmetric encryption applied in modern secure software. Public key cryptography has the significant advantage that two parties can securely exchange data without having to transfer the private key over the Internet. It’s possible to send encrypted data using a widely published public key, to a host that has access to the unpublished private key. Clients encrypt data using the public key, and only the receiving host that has the private key can decrypt the data. Public key cryptography in the form of Rivest, Shamir, Adleman (RSA) key exchange is the core of the more commonly recognized SSL/TLS and HTTPS protocols.

The main use of asymmetric encryption is for sending data over the Internet. The advantage of symmetric key encryption is its speed; it’s significantly faster than asymmetric encryption. If you need to encrypt data for local file system storage, you would likely use a symmetric algorithm.

Modern encryption algorithms rely on the computational difficulty of guessing unencrypted data from its encrypted counterpart. The data from computationally complex encryption algorithms become exponentially more difficult to decrypt by brute force means as the size of the encrypting key grows. Over the years, the size of keys has grown from 56 bits to the now commonplace 256 bits.

Secure Hashing

The need to determine the identity of arbitrary binary information arises for some important tasks in mobile and service development, such as verifying files are not modified during download and determining uniqueness of files in large file sets. Using a secure hashing function provides an answer for this type of problem. A secure hash, or digest, converts data into a single fixed length value, much smaller than the data itself. A good hash function makes it unlikely that digests for various files collide — have the same binary digest value.

Storing Passwords

Another and perhaps more important use for hashing is for the secure storage of passwords. Android applications often need to use passwords to access symmetrically encrypted files and to provide credentials for accessing RESTful web services. As noted, hackers often seek to acquire these passwords to gain the same access as legitimate application code. Consequently, you should not store user credentials for a RESTful service or an encrypted file on a device. Google recommends performing an initial authentication using credentials your app collects from the user, and then using a short-lived, service-specific authorization token (using OAuth or the account manager).

If an application finds it needs to roll its own password storage, it should hash passwords and store their hashed digest — the output of the hash function. When users give their passwords to an application, the application will hash them, and then compare them against already stored digests. If it finds a match, the application accepts the user’s credentials. Modern password storage approaches should include random values, called salt, along with the password and hash both together repeatedly.

Practical Encryption for Android

A few encryption techniques stand out as particularly relevant for writing enterprise Android applications:

  • Advanced Encryption System (AES) is the commonly used symmetric encryption used by applications. It’s fast, modern, and strong. The current AES standard key size is 256; AES(256).
  • HTTPS is the standard secure mode of Internet transport for most web and mobile applications.
  • Secure Hash Algorithm (SHA) provides cryptographically strong hashing with desirable characteristics, such as uniqueness for datasets and low probability of hash collisions. It’s difficult to craft binary data that would contain subtle differences from the data being hashed but still end up with both attack data and original data having the same hash digest. With hashing algorithms, the size of the message digest can be 224, 256, 384, or 512 bits.

Example Code: Symmetric Encryption

It’s time to get started with the first of the chapter examples. This code demonstrates the use of symmetric encryption based on the AES algorithm. You can run the AESEncryption Activity in the sample code to show a string, "This is a demo message from Java!" encrypted and then decrypted. If you need to secure data, you should encrypt data as needed and then write the encrypted text into files as appropriate for your application.

The class AESEncryptionHelper has methods to encrypt and decrypt an array of bytes, as shown in Listing 12-3:

LISTING 12-3: Symmetric encryption on Android (AES-256)

 package com.enterpriseandroid.androidSecurity;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.security.InvalidAlgorithmParameterException;
 import java.security.InvalidKeyException;
 import java.security.NoSuchAlgorithmException;
 
 import javax.crypto.Cipher;
 import javax.crypto.CipherInputStream;
 import javax.crypto.CipherOutputStream;
 import javax.crypto.NoSuchPaddingException;
 import javax.crypto.spec.IvParameterSpec;
 import javax.crypto.spec.SecretKeySpec;
 
 /**
  * Demonstrates the use of symmetric encryption on Android (AES-256)
  */
 public class AESEncryptionHelper {
 
 private String padding =
             "ISO10126Padding"; //"ISO10126Padding", "PKCS5Padding"
 
 private byte[] iv;
 private byte[] key;
 private Cipher encryptCipher;
 private Cipher decryptCipher;
 
 public AESEncryptionHelper(byte[] key, byte[] iv) throws Exception {
     this.key = key;
     this.iv = iv;
 
         initEncryptor();
     initDecryptor();
     }
 
 private void initEncryptor() throws NoSuchAlgorithmException,
             NoSuchPaddingException, InvalidKeyException,
             InvalidAlgorithmParameterException
     {
 
       SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
       IvParameterSpec ivSpec = new IvParameterSpec(iv);
 

Initialize the encryption cipher used to write encryption bytes:

    encryptCipher = Cipher.getInstance("AES/CBC/" + padding);
    encryptCipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
    }
 
 private  void initDecryptor() throws Exception{
    SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
    IvParameterSpec ivSpec = new IvParameterSpec(iv);

Initialize the decryption cipher used to write encryption bytes:

    decryptCipher = Cipher.getInstance("AES/CBC/" + padding);
    decryptCipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
 }
 

This is a generic method for encrypting an array of bytes and it works by writing all bytes to a CipherInputStream that has been configured for AES. The encrypted bytes collect into a byte array output stream, which is converted into a byte[] as a return value.

     public byte[] encrypt(byte[] dataBytes) throws IOException{
         ByteArrayInputStream bIn =
                 new ByteArrayInputStream(dataBytes);
         @SuppressWarnings("resource")
         CipherInputStream cIn =
                 new CipherInputStream(bIn, encryptCipher);
         ByteArrayOutputStream bOut =
                 new ByteArrayOutputStream();
         int ch;
         while ((ch = cIn.read()) >= 0) {
           bOut.write(ch);
         }
         return bOut.toByteArray();
     } 
 

Here is another generic method, this time for decrypting an array of bytes; it works by writing all bytes to a CipherOutputStream that has been configured for AES. As before, the encrypted bytes collect into a byte array output stream, which is converted into a byte[] as a return value.

     public byte[] decrypt(byte[] dataBytes) throws IOException {
         ByteArrayOutputStream bOut = new ByteArrayOutputStream();
         CipherOutputStream cOut =
                 new CipherOutputStream(bOut, decryptCipher);
         cOut.write(dataBytes);
         cOut.close();
         return bOut.toByteArray();    
     }
     
     public static void main(String[] args) throws Exception {

The message to encrypt:

         String demoMessage =
                 "This is a demo message from Java!";
 
         byte[] demoMesageBytes =
                 demoMessage.getBytes();
 
 
         //shared secret
         byte[] demoKeyBytes = "abcdefghijklmnop".getBytes();
 
         // Initialization Vector - usually contains random data along
         // with a shared secret or transmitted along with a message.
         // Not all the ciphers require IV - we use IV in this
         // particular sample
         byte[] demoIVBytes =
                 new byte[] {
                         0x00, 0x01, 0x02, 0x03,
                         0x04, 0x05, 0x06, 0x07,
                         0x08, 0x09, 0x0a, 0x0b,
                         0x0c, 0x0d, 0x0e, 0x0f};
 
         AESEncryptionHelper aesHelper =
                 new AESEncryptionHelper(demoKeyBytes, demoIVBytes);

First encrypt the bytes:

         byte[] encryptedMsg =
                 aesHelper.encrypt(demoMesageBytes);
         System.out.println("Encrypted Msg: " +
                 new String(encryptedMsg));

Print the encrypted data:

         byte[] decryptedMsg =
                 aesHelper.decrypt(encryptedMsg);

Print the decrypted data:

         System.out.println("Decrypted Msg: " +
                 new String(decryptedMsg));
     }    
 }

Now that you can encrypt and decrypt files using AES, it’s time to think about how to handle passwords.

Example Code: Password Hashing

The next code example shows how an application uses a hashed password as a key to a symmetrically encrypted data file, which was created in the previous example. The example hashes the password with salt created from a supplied username. A real-world application of this idea would store the password on a remote service to avoid the security risk of saving the password in the local file system. To decrypt a file with such a key, an application would download the remote password, rehash it, and then decrypt the relevant data. Listing 12-4 generates salt and then performs a shaHex on the password and the salt.


NOTE Listing 12-4 uses a higher-level API, org.apache.commons.codec.digest.DigestUtils, than the one found on base Android. You can find this Apache API at $(CODE)/AndroidSecurity/libs/org.apache.commons.codec-1.3.0.jar.

LISTING 12-4: Password hashing

 package com.enterpriseandroid.androidSecurity;
 
 import org.apache.commons.codec.digest.DigestUtils;
 
 import android.util.Log;
 
 public class PasswordHelper {
 private static final String TAG = "PasswordHelper";
  
 private String passwordHash;
 
     public PasswordHelper(String username, String password) {
         Log.i(TAG, "*****username:" + username + " password:" + password);
         String salt = generateSalt(username);
         Log.i(TAG, "*****salt:" + salt );

Generate the password digest:

         this.passwordHash = DigestUtils.shaHex(password + salt);
         Log.i(TAG, " hash:" + passwordHash);
     }
 

Generate salt:

     private String generateSalt(String s) {
         StringBuffer buf = new StringBuffer();
         for( int i=0; i< s.length(); i++) {
             if ( i % 2 ==0 ) {
                 buf.append(s.charAt(i));
             }
         }
         return buf.toString();
     }
 
     public String getPasswordHash() {
         return passwordHash;
     }
 

Perform a repeat hash as would be required when downloading a password for rehashing to unlock decrypted data:

     public boolean validatePassword(String username, String password) {
         Log.i(TAG, "username:" + username + " password:" + password);
         String salt = generateSalt(username);
         Log.i(TAG, " salt:" + salt );
         Log.i(TAG, " hash:" + passwordHash);
 
         Log.i(TAG, "validate hash:" + DigestUtils.shaHex(password + salt));
         return passwordHash.equals(DigestUtils.shaHex(password + salt));
     }
 }

Encrypting All File System Data

Enterprise and otherwise security conscious users can attain peace of mind by simply encrypting all user data on their devices. Android supports volume-wide data encryption, based on a required phone pin or password (screen lock is not supported). It’s simple to enable file system encryption. Make sure your phone is charged and plugged in, and then select the option with:

Settings -> Security -> Encrypt Phone

WARNING Make certain that you maintain power to your phone during the encryption process. If it fails part way through, you will likely lose all data on your device. It’s definitely a good idea to back up the information on your phone before you start.

Protecting Data in a Database: Preventing SQL Injection

SQL injection attacks are likely the most significant risk to data in a database. This type of attack is easy for hackers to mount and has traditionally yielded significant low-hanging fruit. SQL injection applies to backend services implemented with Hibernate in SQL, but also to Android applications that use SQLite. Chapter 3 noted the peril of manually composing strings to create SQL queries. Recall that the simple use of query, ?, parameters avoids such attacks. In backend services based on Hibernate, a similar approach enables prevention of most injection attacks. Recall the discussion from earlier chapters regarding usage of Android data APIs, specifically where usage of the method:

SQLiteDatabase.query(String table, 
    String[] columns, 
    String selection, 
    String[] selectionArgs,
    String groupBy, 
    String having, 
    String orderBy, 
    String limit)

should always make use of the selectionArgs parameter to replace embedded query occurrences of "?" Developers should never build queries by appending search parameters into a large string. Doing so robs the underlying database engine of the ability to determine the bounds of input parameters, which allows those parameters to include SQL designed to get the database to return results that would otherwise never be part of a response.

Protecting APIs

Android supports a rich interprocess communication model, including Remote Procedure Calls (RPC) based on AIDL, intent-based invocation and broadcasting, and a service model for running tasks in the background. The next sections cover how to build security defenses for these components.

Protecting Intents

The Android Intent system supports generic messaging for Android components. The Intent object carries with it a logical operation to perform (such as, take a picture) and arguments to use (like a URI). When you wrote your first Android application, you declared an intent filter to decide which activity would handle starting your application, as follows:

<activity android:name=".YourActivity" android:label="@string/your_app_name">
    <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
        <category android:name="android.intent.category.LAUNCHER"/>
    </intent-filter>
</activity>

A declaration of an intent filter means that Android should send intents to the declaring component. This opens the door to potential attacks; malicious apps can send intents as easily as legitimate ones. The easiest, but least functional, way to shut them down is to disallow cross process intents by marking components as not exported in your application’s manifest, as follows:

<service android:exported="false"></service>

However, for components that you do export, if malicious code launches your application with attack arguments, it should not end up doing the hacker’s bidding. An intent filter is a good start to adding security. Protect your components by specifying a filter that lists the intents your component can handle, as follows:

<intent-filter>
    <action android:name="com.enterpriseandroid.androidSecurity.DEMO_ACTION"/>
</intent-filter>

The core Android platform defines a set of actions that start with android.intent.action, such as android.intent.action.MAIN or android.intent.action.WEB_SEARCH. You can also define custom intent actions as follows:

<action android:name="com.enterpriseandroid.androidSecurity.DEMO_ACTION"/>

Although intent filters are convenient, application developers should not rely on them as a “securely hardened” API. You should also filter on permission access, as explained in the next section, and should sanitize intent arguments per the domain logic of your application.

Checking the Caller’s Permissions

Your code needs to detect bad arguments and reject those that compromise user security. You can start by looking at the intent methods that provide data to your application, including the following:

getBundleExtra, getCharArrayExtra, getIntExtra

Then make sure you properly sanitize information from these calls, especially if you need to pass intent arguments to sensitive system calls that your application has permission to access. Android has provided a convenient but underused method called Context.checkCallingPermissions for making sure that the call has sufficient privileges to use your application’s privileges.

Listing 12-5 demonstrates how to check the calling permissions for intents that seek to take a picture, access the Internet, and load a URI.

LISTING 12-5: Ensures that calling code has permission to access URI permissions for INTERNET and CAMERA

 1 @Override
 2 protected void onCreate(Bundle savedInstanceState) {
 3     Intent activityIntent = getIntent();
 4     String uriParameter =
 5         activityIntent.getStringExtra(URI_PARAMETER);
 6
 7     Uri uriParam = Uri.parse(uriParameter);
 8     int checkCallingUriPermissions =
 9         checkCallingUriPermission(uriParam,
10             Intent.FLAG_GRANT_READ_URI_PERMISSION);
11     checkGranted(checkCallingUriPermissions,
12         "Uri: " + uriParam.toString());
13
14     String cameraPermission = "android.permission.CAMERA";
15     int checkCameraPermission = checkCallingPermission(cameraPermission);
16     checkGranted(checkCameraPermission, cameraPermission);
17
18     String internetPermission = "android.permission.INTERNET";
19     int checkUriPermission = checkCallingPermission(internetPermission);
20     checkGranted(checkUriPermission, internetPermission);
21 }
22
23 private void checkGranted(int checkPermission, String mesg) {
24     if (checkPermission ==
25         PackageManager.PERMISSION_GRANTED) {
26         Log.d(LOG_TAG, "Permission Granted: " + mesg);
27     }  else if (checkPermission ==
28         PackageManager.PERMISSION_DENIED) {
29         Log.d(LOG_TAG, "Permission Denied: " + mesg);
30     }
31 }
 

The code in Listing 12-5, verifies that the code that launched the given activity has:

  • Lines 11, 12 — Permission to read the URI argument
  • Line 16 — Permission to access the CAMERA
  • Line 20 — Permission to access the INTERNET

So what are the consequences of not using these simple checks? A group of researchers at MIT created a rigorous review of a large number of applications and looked at how they leak privileges using intents. The researchers found that most applications did check for malicious input, but a few did not. As we have mentioned, most intent-related attacks try to get the target application to perform a sensitive operation using permissions it has that the calling code does not. The Android INTERNET permission was the most commonly leaked privilege, where a calling app that does not have the INTERNET permission can pass a URL to load as an intent parameter and direct another app to visit a malicious web page. Unfortunately, the researchers also found that relatively few app developers checked caller permissions. You can learn more about this study as follows:

http://css.csail.mit.edu/6.858/2012/projects/ocderby-dennisw-kcasteel.pdf

Securing Activities

As shown previously, several Android components can receive intents, activities included. However, activities also have a convenient attribute, called android:permission, for ensuring that callers have permission to start a given activity. This attribute obviates some of the need shown previously for writing your own intent checks to ensure the caller has a given permission, but will not perform more detailed inspections of intent parameters, such as URIs. The previous code example shows how to protect intents sent to an activity.

Securing Broadcasts

The Android broadcast API supports delivery of an intent to multiple receivers in different applications. An Android component sending a broadcast does not see a list of all receivers of the intent, nor does a receiver have knowledge of what code might be sending it intents. Consequently, filtering of intents gains significant importance, as does ensuring that receivers have permission to receive and senders have permission to send. Fortunately, Android supports ways of enforcing security for both ends of broadcast intent delivery.

Receiving Broadcasts

Broadcast receivers can receive intents for which they did not register, which means developers should be vigilant in filtering their inputs, and only accept broadcast actions that they are designed to accept, as discussed previously. Like the activity tag, the <receiver> tag also supports the android:permission attribute, but it’s still advised that you perform detailed caller permission checking on receiving a broadcast intent.

The following example broadcast receiver requires that all senders have the RECEIVE_BROADCAST permission. Additionally, the receiver only accepts intents with action DEMO_ACTION:

<receiver android:name=".AndroidSecurityBroadcastReceiver"
    android:permission=
        "com.enterpriseandroid.androidSecurity.permission.SEND_BROADCAST">
    <intent-filter>
        <action android:name=
            "com.enterpriseandroid.androidSecurity.DEMO_ACTION"/>
    </intent-filter>
</receiver>

Sending Broadcasts

It’s straightforward to send a broadcast intent and require that a receiver have a particular permission to receive, in this case, RECEIVE_BROADCAST:

Intent secureIntent = new Intent("RECEIVE_BROADCAST");
String receivePermission =
    "com.enterpriseandroid.androidSecurity.RECEIVE_BROADCAST";
sendBroadcast(secureIntent, receivePermission);

Note that receivers that register for the given action, but do not have the specified permission, will simply not receive the message. Android does not throw a security exception, but instead just blocks the receivers from getting the message.

Services

Android can limit the processes that have the ability to bind or interact with a given service component, by again requiring permission for these operations. The android:permission attribute supports this restriction as follows:

<service
    android:name="SecurityDemo"
    android:permission="com.enterpriseandroid.androidSecurity.SERVICE_BIND"
    android:exported="true"
    android:enabled="true"
    >
 
    <intent-filter>
        ...
    </intent-filter>
</service>

where you can simply add the permission required for binding to the service declaration. Service operations for starting and stopping all require the specified permission as well.

Content Provider Security

As you’ve seen in earlier chapters of this book, content providers should be a central part of the data management strategy for your application.

Securing Custom Content Providers

Android provides read and write permissions to limit content provider access to only privileged clients. As you’ve seen, it’s a good idea to use the principle of least privilege to write applications that request read or write access as they need it (for example, to not request read and write, if they only need read). Application developers should also keep in mind that write access does not imply read access. Consider the sync adapter pattern from earlier chapters that reads data from a backend service and pushes it into a content provider, but does not need to read the data it writes; actually the Migrate sync adapter works along these lines. Listing 12-6 shows a provider declaration that requires read and write permissions.

LISTING 12-6: Content provider declaration that requires read and write permissions

<provider
    android:name="com.enterpriseandroid.contacts.ContactsProvider"
    android:authorities="com.enterpriseandroid.contacts"
    android:readPermission="com.enterpriseandroid.contacts.READ_CONTACTS"
    android:writePermission="com.enterpriseandroid.contacts.WRITE_CONTACTS"
    >
</provider>

When a user has granted permissions as needed to an app, it can invoke content resolver or content provider methods to query, insert, update, and delete contacts. An application that invokes a query but does not have the READ_CONTACTS permission will cause the platform to throw a SecurityException, and likewise the same will happen for a caller that does not have WRITE_CONTACTS but still calls insert, update, or delete.

Sharing Permissions

Read and write access is the minimum control you need to protect content provider data. URI permissions provide an important fine-grained provider access control. They enable content providers to limit access to data for specified namespaces. Consider that the contacts content provider might have grouped contacts into business and personal categories. The following URIs reflect this organization:

content://com.enterpriseandroid.contacts/business
content://com.enterpriseandroid.contacts/personal

When applications need to share subsets of data, Android does something clever; it enables a dynamic permission grant from one application that already has permission to read or write to temporarily give a specified subset of these same permissions to another application. Imagine a contacts application that needs to share a contact with a vCard application. Assuming the contacts application has full access to the contacts provider when it launches an intent to be handled by the vCard application, it can specify in the intent that the vCard application should also have permission to read the data it needs to display a virtual card. Listing 12-7 shows a provider declaration that enables this type of dynamic grant for the contacts content provider.

LISTING 12-7: A provider declaration that allows dynamic grants to the business and personal categories

<provider
    android:name="com.enterpriseandroid.contacts.ContactsProvider"
    android:authorities="com.enterpriseandroid.contacts"
    android:readPermission="com.enterpriseandroid.contacts.READ_CONTACTS"
    android:writePermission="com.enterpriseandroid.contacts.WRITE_CONTACTS"
    >
        <grant-uri-permission android:pathPrefix="/business/"/>
        <grant-uri-permission android:pathPrefix="/personal/"/>    
</provider>

The code to launch an intent that grants a dynamic permission consists of creating the intent, setting a data URI, and then setting Intent.FLAG_GRANT_READ_URI_PERMISSION, which causes Android to grant the permission to the receiving application. See Listing 12-8.

LISTING 12-8: Code that launches an intent to show a vCard

Uri contactUri = 
    Uri.parse("content://com.enterpriseandroid.contacts/business/1");
 
Intent vcardIntent = new Intent(Intent.ACTION_VIEW);
vcardIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
vcardIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
vcardIntent.setDataAndType(contactUri, "image/png");
startActivity(vcardIntent);

Figure 12-2 illustrates the sharing of dynamic permission grants:

Note that Android supports wildcarding in provider grant URI declarations. The following example shows an intent that can grant all categories starting with personal, or business followed by a single character:

<grant-uri-permission android:pathPrefix="/personal.*/"/>
<grant-uri-permission android:pathPrefix="/business.*/"/>

In this case, "." means match any single character and "*" means match one or more occurrences of the preceding character.

Example Code: Protecting RESTful Invocations

As this chapter has shown, most forms of data on a mobile device present lucrative hacking targets, worthy of encryption and careful handling. Sending this information over whatever Internet connection your device happens to be using has serious security implications. Who knows whether or not a hacker is peering at your application traffic using Wireshark on WiFi at the nearest cafe?

Service Authentication

When a client opens a secure connection, a public key handshake takes place that enables an Android client and backend service to communicate over an encrypted communication stream. As you saw in the discussion of public key encryption, the public key enables encryption by all, but decryption only by the holder of the private key. Unfortunately, a guarantee of encrypted communication does not mean a client can be certain of the identity of the service to which it is connected since an unknown public key does not have any distinguishing features by itself.

To enable clients to authenticate the service, all HTTPS sessions make use of digital certificates, which provide a way to ensure that a client can trust a public key for a given service host. As part of the secure handshake, the service will send its certificate to the client. Secure certificates work on a model of transitive trust, whereby a certificate authority (CA) issues certificates that individual websites distribute. Most OS platforms hold a system keystore that contains well known certificate authorities like VeriSign, Google, and so on. When a client downloads a site certificate, it can verify that an already known certificate authority digitally “vouches” for the new certificate.

The hostname of a web service is encoded into each service certificate, which means that the client can extract the name encoded in the certificate, compare it to the DNS name to which it opened its connection, and make sure that they are the same. The combination of hostname and CA validation allows the Android client to trust the identity of the target service.


NOTE It’s a financial advantage for a company to have a root CA pre-installed in Android, in iOS, and in web browsers. Many certificate authorities exist to charge developers a fee for certifying communication of site certificates.

Code Example: Securing the Chapter 6 Contacts Service Communication

As noted previously, web browsers and Android applications secure Internet traffic using HTTPS, which encrypts data sent between a client and web server and eliminates the risk of a “man in the middle” attack. It’s not computationally feasible for an eavesdropper on the network to read the communication. In this code example, you’ll invoke a secure request on the Chapter 6 $CODE/springServiceContacts service. You’ll make this request using HTTPS by setting up secure communication on the client and backend service, with the following steps involved:

1. Securing the Chapter 6 contacts web service:
a. Creating a “Certificate Signing Request”
b. Creating your own CA (optional)
c. Obtaining a site certificate for service authentication
d. Configuring an HTTPS transport for Tomcat: with JSSE or APR
e. Authenticating the service using basic authentication
2. Invoking a secure connection to the service from Android using HTTP basic authentication

Securing the Chapter 6 Contacts Service

The task of securing a backend web service for an Android application can be quite easy, but securing services with a moderate level of complexity provides significant challenges as hackers find clever ways to get past your defenses. This chapter only covers the straightforward steps involved in securing the RESTful web services from Chapter 6, as follows:

  • Creating a site certificate and adding it to a keystore for authentication
  • Modifying the Chapter 6 Spring application context to support basic authentication
  • Configuring a demonstration user who can log into the Chapter 6 service

The next few sections walk through implementing these tasks using the code in $CODE/springServiceContacts.

Creating a “Certificate Signing Request”

Before buying or signing your own certificate, you will need to create a “Certificate Signing Request” that you can send to a commercial CA, or sign yourself (with instructions that follow). You can learn more information about this request online:

http://en.wikipedia.org/wiki/Certificate_signing_request

The following steps for creating this request are based on the OpenSSL tool, which is pre-installed on Linux and Mac OS:


NOTE When you run the commands that follow, you should answer all of the questions, and answer them consistently (for example, use the same city in all responses).

1. If you are using Windows, you need to install cygwin software from the following location:
as described in chapter 6.
2. Start a shell on your particular platform. On Windows, double-click Cygwin-Terminal. The example assumes that the SSL software is located at:
/usr/bin/openssl
3. Create a CA working directory in $CA_DIR/AndroidSecurity/cadir these instructions refer to it as CA_DIR — and change directory to it:
cd $CA_DIR
Run all commands from this directory.
4. Create a private key as follows:
/usr/bin/openssl genrsa -out contacts_privkey.pem 1024
5. Create a certificate as follows:
/usr/bin/openssl req -new -x509 -key contacts_privkey.pem -out 
contacts_cert.pem
Note that when you generate the certificate, the common name should be the exact fully qualified hostname, FQDN, of the service site; it will be accessed from the Android client.

NOTE Please keep in mind that the FQDN you choose for your site must be an actual resolvable DNS hostname from whatever Android environment you use — the Android emulator or an Android device. It’s a good idea to load the site name as a web page in the Android browser to make certain Android can really see it. Note also, that the DNS name must not use a known root domain like amazonaws.com, but must be your own domain. Hover.com is a good place to buy a domain name if you don’t already have one.

6. Create a “request to sign” the certificate, by concatenating the certificate from Step 5 with the private key from Step 4, as follows:
cat contacts_cert.pem contacts_privkey.pem |/usr/bin/openssl x509
-x509toreq -signkey contacts_privkey.pem -out contacts_certreq.csr 

Now that you have a signing request, you can choose to do one of two things with it:

  • Pay a fee to have a commercial certificate authority, such as VeriSign or StartSSL to sign it. This service varies widely in price, but starts at about $150 for a 2-year certificate.
  • Create your own certificate authority, recognized by all the applications that you write, and sign the certificate yourself.

Creating Your Own CA

As previously discussed, a service needs a certificate for secure handshakes with clients. It turns out that with mobile applications it’s entirely possible to become your own certificate authority and avoid any hassle associated with buying certificates. You can create as many of your own free and valid certificates as you need. If you want to become your own certificate authority, run the following utilities, as per your platform:

1. Create a new CA:
Linux:
/usr/lib/ssl/misc/CA.pl –newca
Mac OS:
/System/Library/OpenSSL/misc/CA.pl -newca
Cygwin:
perl /usr/ssl/misc/CA.pl –newca
2. As you run the CA.pl program, answer all questions as follows:
a. Press Enter when the tool asks for the CA certificate filename.
b. Enter a PEM passphrase.
c. Pick values for locality and organization.
d. The common name is the name of your certificate authority; choose an appropriate name (for example, “my root CA”).
e. Choose passphrases as appropriate.
f. Enter your e-mail.
g. Enter a challenge password.
h. Enter the passphrase from Step b (make certain you enter it correctly).

Don’t skip any field, record what you enter, and re-use your answers in future steps.

When the program completes, you should have the files you need to act as your own CA. Your CA certificate should now reside in demoCA/cacert.pem, and you can start signing certificates with it. Note that the default expiration period of certificates that you sign with your CA is 365 days, as specified in the CA.pl script. If you need to make the time period longer, you’ll need to modify CA.pl to change the duration.

Obtaining a Site Certificate for Service Authentication

Now sign the certificate request from Step 6 of “Creating a ‘Certificate Signing Request’” with the files generated in demoCA. Run the following command using the output, demoCA directory from “Creating your own CA” (note that the command “knows” the directory name, demoCA):

/usr/bin/openssl ca -policy policy_anything -in 
contacts_certreq.csr -out contactservice.pem
1. Enter the passphrase from Step 2, b of the “Creating Your Own CA” section and sign and commit the new certificate.
2. Make sure that the size of contactservice.pem is not zero — this file contains your new certificate. Note that you can only sign each cert request once.
3. You can now add contactservice.pem to web service backends to communicate using HTTPS with Android applications. You will add $CA_DIR/demoCA/cacert.pem to the root store of your Android client, explained shortly.

Configuring an HTTPS Transport for Tomcat: with JSSE or APR

Now that you have a certificate, you can start the process of setting up Tomcat to use it and exporting the contacts service with an HTTPS transport. You can configure Tomcat to use your certificates in two ways:

  • Using Java Secure Sockets (JSSE), generally used with production deployments
  • Using a native technology called the Apache Portable Runtime, which is often used in development deployments
Configuring Tomcat Using JSSE
1. Create a service keystore and import the contact private key and service certificate into it.
Tomcat will use the keystore to support HTTPs with the contacts service. Server-side Java supports the keystore file format “JKS” for storing certificates and a utility for editing it called keytool.
You’ll create the keystore and import the contacts service certificate into it. This is either the commercially signed certificate or your own CA signed certificate called contactservice.pem. First, JSSE requires a different certificate format, called DER. Use the following commands to convert your files into the DER format.
Convert the private key:
openssl pkcs8 -topk8 -nocrypt -in  contacts_privkey.pem -inform PEM -out 
contacts_privkey.der -outform DER
Convert the signed certificate:
openssl x509 -in contactservice.pem -inform PEM -out contactservice.der 
-outform DER
It’s common to use keytool to edit Java keystores, but in this case, you will need to use a Java utility to import the converted certificate files into the keystore. You can download it from the following location:
Or you can use the version included in:
$CODE/AndroidSecurity/ImportKey.java
Edit the file to set your keystore password — change the variable, keypass. For consistency, use the same passphrase you used in the “Creating Your Own CA” section Step 2, b (if you did that step); otherwise, pick a password.
Compile this utility using the following in the $CA_DIR:

NOTE Commands assume that java and javac are in the system classpath.

javac –d . ../ImportKey.java 
Run ImportKey to create the keystore and import the private key and contacts certificate, as follows:
java -Dkeystore=<cadir>/tomcat_keystore.jks ImportKey <cadir>/contacts_
privkey.der <cadir>/contactservice.der
You should be able to list the contents of the keystore using Java’s keytool:
keytool -list -v -keystore tomcat_keystore.jks
keytool resides in $JAVA_HOME/bin, which should be in your system path.
2. Edit the Tomcat server configuration file, called $CATALINA_HOME/conf/server.xml, by uncommenting the 8443 ssl connector to make it active. Edit the fields to match the following code:
<Connector port="8443" maxThreads="200"
  scheme="https" secure="true" SSLEnabled="true"
  keystoreFile="<ca_dir>/tomcat_keystore.jks" keystorePass="<your_password>"
  clientAuth="false" sslProtocol="TLS"/>
3. Enter the password from “Creating Your CA” or the password you used for your commercial certificate. Change ca_dir to be the directory where your CA authenticated private key resides.
4. Restart Tomcat.
Configuring Tomcat Using APR

APR is significantly easier to configure than JSSE. You can just use the certificates you have created by directly configuring them into the Tomcat configuration file, $CATALINA_HOME/conf/server.xml, as follows:

<-- Define a SSL Coyote HTTP/1.1 Connector on port 8443 -->
<!--
<Connector 
           port="8443" maxThreads="200"
           scheme="https" secure="true" SSLEnabled="true"
           SSLCertificateFile="<ca_dir>/contactservice.pem" 
           SSLCertificateKeyFile="<ca_dir>/contacts_privkey.pem"
           clientAuth="optional" SSLProtocol="TLSv1"/>
-->

NOTE Replace ca_dir with the directory where the contactservice.pem resides. contactservice.pem is the result of either your personal CA or signing with a commercial CA.

Once you have edited server.xml, you’ll need to complete one last task: Edit $CODE/springServiceContacts/applicationContext-rest.xml and uncomment the following line:

      <!--<security:http-basic/>-->

as documented in the file. Then rebuild springServiceContacts and deploy the project war to Tomcat. Now that you have a secure backend, it’s time to move on to creating a secure connection to it from Android.

Opening a Secure Connection on Android

As noted in Chapter 5, Android supports a number of ways to open a secure connection. Listing 12-9 demonstrates how to do so using the Apache framework, but you could also use the Spring framework for Android. The example shows that it’s a pretty simple operation; you just need to create a connection manager and socket factories for each of the ports you will serve — a secure one for HTTPS and a plain text factory for unencrypted port 80. This example allows you to use the certificates signed using a commercial certificate and your own root CA.

LISTING 12-9: Secure connection using the Apache framework

package com.enterpriseandroid.androidSecurity;
  
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
 
import org.apache.http.client.HttpClient;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
import android.content.res.Resources;
 
/**
 * Creates an Https client that loads a keystore that can supply an
  * application defined root certificate authority to validate the client
  * connection.
  *
  * This client can also authenticate using the system keystore which
  * contains standard CAs as well.
  */
 public class HttpsClientHelper {
     public static HttpClient getHttpClient(Resources resources)
             throws KeyManagementException, UnrecoverableKeyException,
             NoSuchAlgorithmException,
             KeyStoreException, CertificateException,
            IOException
     {

If you created “your own CA,” the following code provides the implementation of the method for avoiding paying for a valid certificate. The code loads your own root CA from a trusted keystore stored in a raw file.

Note though that the format of the keystore must not be “JKS” as used with Tomcat. It needs to be, “BKS” — for Bouncy Castle Keystore, which is the only format that Android supports. To use your own CA certificates, you will need to import the file <cadir>/demoCA/cacert.pem into a BKS keystore.

You will need to use a utility to import the converted certificate files into the keystore. Download the following useful graphical tool, called Portecle, for this task:

http://sourceforge.net/projects/portecle/

Unzip the download file and then run Portecle using the following command line from the unzipped directory:

java –jar <unzip_dir>/portecle.jar

Using the portecle UI, import your CA certificate into a new keystore, which should be of type BKS, and save it into the following directory with the name listed as follows:

$CODE/AndroidSecurity/res/raw/your_ownca_keystore.bks 

Record the password for the keystore. For convenience, you can use the same password you used previously.

When asked, confirm that the certificate is trusted and accept the alias (for example, my root ca); ignore the previous instructions, and comment out the lines to load the BKS keystore.

         KeyStore localRootStore = KeyStore.getInstance("BKS");
         // Contains your application's root CA and allows use of
         // certificates that you sign with that CA.
         InputStream in = resources.openRawResource(R.raw.your_own_ca_keystore);
         localRootStore.load(in, "changeit".toCharArray());
 

A scheme registry will hold the socket factories for port 80 and 443, non-secure and secure.

         // Use unencrypted factory for http port 80
         SchemeRegistry schemeRegistry = new SchemeRegistry();
         schemeRegistry.register(new Scheme("http",
             PlainSocketFactory.getSocketFactory(), 80));
 
         // Use a secure socket factory for 443, but this socket
         // factory will consider our "root" trust store when
         // making its connection.
         SSLSocketFactory sslSocketFactory =
             new SSLSocketFactory(localRootStore);
         schemeRegistry.register(new Scheme("https",
             sslSocketFactory, 443));
         HttpParams params = new BasicHttpParams();
         ClientConnectionManager cm =
             new ThreadSafeClientConnManager(params,
             schemeRegistry);
 
         HttpClient client = new DefaultHttpClient(cm, params);
         return client;
     }
 }

This code configures an HTTP client that can connect to the Chapter 6 service as follows:

  • Loads a keystore to use as a root store — the store can contain the root CA created in previous sections.
  • A schema registry holds socket factories for HTTP and HTTPs.
  • The SSL socket factory uses the previously loaded keystore as a root store, which enables validation of certificates signed using your own root CA as well as certificates signed by commercial CAs.

Authorizing the Client

Just like the service’s site certificate enables the client to trust the host to which it is connecting, the client also needs to authorize its user to the service. Modern mobile and web applications use two standard modes of authentication — HTTP basic authentication and a protocol called OAuth. HTTP basic authentication is by far the most common mechanism for authenticating users to backend services. However, due to greater flexibility, OAuth is quickly replacing HTTP basic as the de facto authorization for accessing service resources.

The various RESTful APIs for Android all directly support HTTP basic. To provide a bit more detail, HTTP basic makes use of a header and a base-64 encoded username:password to transmit credentials in every RESTful invocation of a secure backend service. When using HTTP basic, applications don’t so much as log in to a service, as they simply collect user credentials that can be attached to authorize every RESTful request. Readers familiar with JavaScript will recognize the code used to add basic authentication to an AJAX request:

import base64
encodedAuth = base64.encodestring('%s:%s' % (username, password))[:-1]
req.add_header("Authorization", "Basic %s" % encodedAuth)

The resulting header looks like the following:


Authorization: Basic FJkjuekjDFJskjDKlFJSksfspt==

Listing 12-10 finishes the secure invocation with an example snippet of how to do basic authentication in Java for Android.

LISTING 12-10: HTTP basic authentication in Java for Android

 UsernamePasswordCredentials credentials =
     new UsernamePasswordCredentials(user, pass);
 

The code creates a new instance of the HTTPS client utility helper.

 HttpClient httpClient =                       
     HttpsClientHelper.getHttpClient(mContext.getResources());

It then creates a new AuthScope that holds the basic credentials:


  AuthScope as = new AuthScope(host, 443);
      ((AbstractHttpClient) httpClient).getCredentialsProvider()
          .setCredentials(as, credentials);

It then creates a new basic contact and sets the basic auth header:

 BasicHttpContext localContext = new BasicHttpContext();
 BasicScheme basicAuth = new BasicScheme();
      localContext.setAttribute("preemptive-auth", basicAuth);               

It then creates a new HTTP request and executes the request with attached credentials to authenticate the client:

 HttpHost httpPost = new HttpHost(host, 443);                
 HttpResponse response = 
      httpClient.execute(httpPost, getRequest);
 response.getStatusLine();
 

Running the Example Client

Now that you’ve seen all relevant concepts, you can run the example:

Launch your securely modified springServiceContacts using the configuration changes listed previously.

Make sure to enter the hostname from Step 5 in “Creating a ‘Certificate Signing Request’” into the following field:

SecureConnectionActivity.SECURE_HOST

Additionally, set the password to your BKS keystore in HttpsClientHelper.CAPASSWORD.

Then run the SecureConnectionActivity in $CODE/AndroidSecurity project (choose the secure connection option).

OAuth

Although basic authentication may be common, superior forms of authentication have come into common usage on the Internet. Specifically, OAuth allows clients to access server resources without the liability of using passwords, much like the Android account manager. Clients access user data on behalf of a user, and access a set of resources available under an OAuth ID, which is a one-time temporary identifier that cannot leak the same way as a password. This version of Enterprise Android does not provide a code example for OAuth, but you can learn more about it in relation to Android at the following URL:

http://developer.android.com/training/id-auth/authenticate.html

Android Account Manager

Android APIs greatly simplify the task of managing passwords with the inclusion of the android.accounts.AccountManager API, which allows an application to list service accounts registered on the system (for Google, Facebook, and MS Exchange, and of course, the Migrate sync account from Chapter 10).

Applications can manage accounts, and most importantly can obtain authorization tokens from them in the style of OAuth. Specifically, the account manager precludes the need for the application to store passwords to remote services.

The URL referenced in the previous section leads to explanations in detail of how the account manager works with OAuth.

Android Account Manager Example

This section contains a simple exploration of how the Android account manager works. The chapter includes code to access the account manager, to list its accounts, and to obtain an auth token from one account.

The code lists Android accounts, looking in particular for the Migrate account, and then acquires an auth token from it for display. In a real usage, the auth token could be used for authorization to access service resources. See Listing 12-11.

LISTING 12-11: A simple demonstration of the Android account manager

 package com.enterpriseandroid.androidSecurity;
 
 import android.accounts.Account;
 import android.accounts.AccountManager;
 import android.accounts.AccountManagerCallback;
 import android.accounts.AccountManagerFuture;
 import android.accounts.AuthenticatorException;
 import android.accounts.OperationCanceledException;
 import android.app.Activity;
 import android.content.Intent;
 import android.os.Bundle;
 import android.util.Log;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.widget.Button;
 import android.widget.TextView;
  
 
 /**
  * Use the Android account manger to lists accounts and get
  * an auth token from the Migrate account setup for Chapter 10.
  */
 public class AuthTokenActivity extends Activity{
 /** The tag used to log to adb console. **/
     private static final String TAG = "AuthTokenActivity";
     private static final String ACCOUNT_TYPE="myAccountType";
     
     private AccountManager mAccountManager = null;
    
     @Override
     public void onCreate(Bundle savedInstanceState) {
         
         super.onCreate(savedInstanceState);
         setContentView(R.layout.auth_token_activity);
         final Bundle bundle = savedInstanceState; 
         try {
             mAccountManager = AccountManager.get(this);

Access and display the Android accounts:

             Account [] accounts =
                     mAccountManager.getAccounts();
             String accountsList =
                     "Accounts: " + accounts.length + "
";
             for (Account account : accounts) {
                 accountsList += account.toString() + "
";
             }
             setText(R.id.message, accountsList);
              
         } catch (Exception e) {
           setText(R.id.message, e.toString());
         }
          
         Button loginBtn = (Button)
                 findViewById(R.id.login);
         loginBtn.setOnClickListener( new OnClickListener() {           
             public void onClick(View v) {
                 try {
                     Account [] accounts =
                             mAccountManager.getAccounts();
                     if (accounts.length == 0) {
                         setText(R.id.result, "No Accounts");
                         return;
                     }
                     Account account = accounts[0];

Obtain the auth token for the Migrate account:

                     mAccountManager.getAuthToken(account,
                             "com.migrate.webdata.account", bundle,
                             false, new
                             accountManagerCallback(), null);
                 } catch (Exception e) {
                   setText(R.id.result, e.toString());
                 }
             }
         });
     }
     
    
     private class accountManagerCallback implements
             AccountManagerCallback<Bundle>
     {
         public void run(AccountManagerFuture<Bundle> result) {
                 Bundle bundle;
                 try {
                         bundle = result.getResult();
                         Intent intent =
                                 (Intent) bundle.get(AccountManager.
                                         KEY_INTENT);
                         if(intent != null) {
                             // asked user for input
                             startActivity(intent);
                         } else {
                           setText(R.id.result, "auth token: " +
                           bundle.getString(AccountManager.KEY_AUTHTOKEN));
                         }
                 } catch (Exception e) {
                   Log.e("TAG", "accountManagerCallback failed: " + e);
                   setText(R.id.result, e.toString());
                 }
         }
     };
      
     public void setText(int id, String msg) {
         TextView tv = (TextView) this.findViewById(id);
         tv.setText(msg);
     }
      
 }

Now that you can secure and authenticate both ends of a secure invocation between an Android client and a backend service you’re well on your way to writing secure enterprise Android applications that you can deploy to a variety of major cloud vendors. Now it’s time to shift focus to how to protect your Android applications from theft.

Preventing Piracy

Android is designed to be an open platform on which users can install applications from different vendors. Pretty much anyone can create and install an application for Android, with few limitations. It’s even possible to download and install entirely new application stores. This flexibility afforded to users does not come without cost to application developers.

Recall the earlier discussion regarding keeping malware off user devices that noted how Android supports several sources from where users can install applications onto Android devices. These sources include the Google Play and Amazon app stores, installing from unknown sources on the Internet, and side loading from SD cards. In contrast, with iOS, Apple allows application installation only from the Apple App store (not counting “jail-broken” devices). Also consider that the Internet has no shortage of industrious hackers eager to break or pirate successful applications so that they can be installed and used free of charge.

The bottom line is Android allows easy installation of pirated applications, as long as users are willing to risk malware infection, assuming they consider the possibility at all. Indeed, many application developers have voiced concerns regarding the ease with which users can install pirated applications. As an example, the first person shooter game “Dead Trigger” dropped its price from $0.99 to free due to extremely widespread piracy:

http://www.androidcentral.com/how-high-unbelievably-high-piracy-dead-trigger-devs-not-saying

Some estimates state the revenue for Android applications is as much as 40 percent less than the same or comparable applications on iOS.

The Google Play licensing service is one way to protect revenue from your Android applications from piracy. The Google Play app store provides a license verification service that verifies whether the current user has a valid license. The application can decide to shut the app down or provide appropriate behavior when a user attempts to run an app without a license. You can find out more about the licensing service here:

http://developer.android.com/google/play/licensing/index.html

SUMMARY

This chapter began by covering the steps that handset users can take to keep malicious applications off their phones. This coverage included a walkthrough of tools from Google and a few other vendors, as well as security reviews of these utilities; it turns out that there is still quite a bit of risk involved when users install applications from unknown vendors. The chapter then moved to present results from the malware genome project and discussed types of security attacks for which application developers should build defenses in their applications. The chapter included an introduction to Android permissions, and promoted an understanding of those permissions as informed by the results of the malware genome project. The chapter directed developers to consider typical application weaknesses and to understand the ingredients of applications that could protect them, which included:

  • Secure use of permissions
  • Protecting data
  • Protecting communication
  • Preventing piracy

The chapter included practical demonstrations of these security tenants in the form of:

  • Various code snippets regarding permission use
  • An example data encryption using symmetric AES256
  • A demonstration of secure password hashing based on SHA256
  • An HTTPS version of the RESTful contacts service
  • An example of how to use the Android account manager

In conclusion, application developers should keep in mind that while Google and other developers are constantly improving malware defenses, malware is also in a race to circumvent safeguards to profit from theft and invasion of user privacy. Developers should consider how users will protect their devices, write their applications to defend against attacks, and beware the significant consequences of lapses in security. To avoid security holes, follow the precautions discussed in this chapter and in the Android developer documentation and stay current with the latest in Android security news.

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

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