“Eternal vigilance!” is the watchword for developing mobile devices and applications. However, implementing random security techniques in your app as a result of blind panic is hardly a good development strategy. As you design your app, think systematically to see where the security principles described in this chapter apply, and then implement the necessary security using a combination of the techniques also described in this chapter.
In this chapter, we take a holistic look at developing secure Android apps — starting by describing why security is especially important for mobile apps, and then presenting security principles and general security techniques. We then get into Android security specifics.
Security is an increasingly important consideration for mobile devices (and their applications), for three primary reasons:
Because an app is now the primary means of using a device, it creates a security risk. Keep in mind that mobile apps have been authored by a range of organizations and developers and have been installed from diverse locations. Depending on the permissions granted to an app, it may be able to read and create user data on the device. In the Android Application Model, an app can be launched directly from the Home screen or invoked by another app. These two characteristics (it can read or create private data and it can be invoked by another app through an Intent — Chapter 3) make every app — including yours — a potential security risk. This is because your app, if it has access to private data and can be invoked by another (malicious) app, can be forced to reveal this data. Creating private data is a problem in itself. If your app creates private data and leaves it on the device in an insecure manner, a malicious piece of code (such as another app) can read it.
Here are some other reasons that mobile devices are more vulnerable than desktop computers:
For example, some financial portals show users special, personalized images to verify that they're on legitimate websites. Someone using a desktop in an office setting is likely to notice that this image is missing after being directed to a site that's spoofing the legitimate site. A user on a mobile device, on the other hand, is likely to be distracted and not notice the missing image because of simultaneously having to navigate the interior of a shopping mall or attempt to maintain balance on a speeding train.
When your application is demonstrably safe, secure, and useful, it becomes an application that people trust and hence want to buy, download, and install. While the reliable, high-performing usefulness of an application is certainly a significant factor in establishing trust (trust happens as a side-effect of the app demonstrating it can “get the job done well”), security plays the largest role in establishing trust.
An application developer wondering how to provide application security typically starts by considering specific (but random) topics such as types of encryption and password-based login.
However, as an app developer, you must first define the app's threat model, which defines the kinds of attacks the app must expect to handle, the assets that must be protected, and the likely degree of loss if those assets are violated or stolen. (See the later section “Defining the Threat Model for an Android Application.”)
After you have defined the threat model, you need to identify the specific techniques to handle threats. Security techniques can be grouped in the following functional categories:
Another (related) classification of security techniques is defined by the roles that the above security techniques can play in implementing a secure system. There are four roles, as follows:
Use both the lists to guide you in finding out how to address the attacks the system is likely to face. This systematic approach can lead to much better protection of your app than does simply adding a few ad hoc security techniques. Incidentally, the set of threats the system is likely to face, the probabilities of the threats succeeding, and the losses that are likely to happen if the threats succeed are collectively known as the “threat model” for a system. We explain the threat model, and how to define it, in the next section.
To define the threat model, this section describes what types of Android vulnerabilities you have to (and don't have to) deal with.
On the good side, because Android is a privilege-separated operating system. This means that — because it runs on Linux — every application runs under its own user ID and group ID. In other words, applications run separately from each other and the system. Finally, whenever an application is uninstalled, all its private data (including preferences and SQLite databases) is removed. Many risks are therefore eliminated and do not need to be included in the threat model.
On the bad side (it's not the fault of Android, however), after your app has been downloaded to a device, virtually every one of its characteristics can be looked up by an attacker, because the .apk file can be parsed and all its separate components extracted, including the manifest file, executable code, resources, and images. The source code can then be decompiled (reconstructed) from the executable code and examined for useful information such as which algorithms are used and which strings represent user IDs and passwords. As you might imagine, implementing “security by obscurity” — that is, relying on the system being safe because no one knows anything about it — simply isn't possible. You have to assume that an attacker knows every detail about your app and then try to protect it.
Your application can become a security risk in six ways, for example, if you
The following sections look systematically at how to address these threats.
The security threat in your app lies in malicious code — or a malicious user — taking advantage of the capabilities granted to your application.
Let's start by looking at how your app gains those capabilities. Android's privilege model (the rules by which capabilities are granted to applications) is designed so that no application can, by default, give permission to do anything that can adversely affect other apps or the operating system. Essentially, every app runs in its own sandbox (for example, its own address space in memory, or its own processes, threads, and space on the file system). If your app needs to operate outside this sandbox, such as by launching another app, by using some system functionality, or by sharing resources with another app, it must explicitly ask for permission from the Android framework.
All Android applications (specifically the .apk files that are installed on the device) must be signed using a certificate that identifies the author of the application. Self-signing certificates are perfectly legal — certificates don't have to be signed by a signing authority that verifies your identity. Android just wants to be able to uniquely differentiate you from everyone else.
For this reason, you can ask for a couple different kinds of permissions:
A particular permission can be enforced at a number of places during your app's operation:
The following XML snippet shows examples (from the Tic-Tac-Toe application) of requesting permission to use the Internet, access the network state, find both coarse and fine locations, and read contacts from the built-in Contacts application. You can see the complete list of permissions at http://developer.android.com/reference/android/Manifest.permission.html. Note that this list isn't static but, rather, grows in each Android release. Neither does it contain the list of custom permissions defined by you (see the entry containing LAUNCHACTIVITY shown in the XML block below).
<uses-permission android:name=“android.permission.READ_CONTACTS” /> <uses-permission android:name=“android.permission.INTERNET” /> <uses-permission android:name=“android.permission.ACCESS_NETWORK_STATE” /> <uses-permission android:name=“android.permission.ACCESS_COARSE_LOCATION” /> <uses-permission android:name=“android.permission.ACCESS_FINE_LOCATION” /> <uses-permission android:name=“com.wiley.fordummies.androidsdk.tictactoe.LAUNCHACTIVITY” />
Note carefully where the <uses-permission> … </usespermission> element is placed in the AndroidManifest.xml file (it must be outside the application block and inside the manifest block)!
In the preceding chunk of code, you can see that the last permission appears to be specific to the Tic-Tac-Toe application — and it is. In addition to requesting predefined system permissions, apps can define their own permissions. To define and use custom permissions, these three steps must take place:
<permission android:name=“com.wiley.fordummies.androidsdk.tictactoe.LAUNCHACTIVITY” android:label=“Launch Tic-Tac-Toe Activity” android:description=“@string/permission_launch_activity” android:protectionLevel=“normal” />
Note carefully where this element is also placed in the AndroidManifest.xml file (outside the application block and inside the manifest block). Also, the complete list of attributes in the permission element is shown at http://developer.android.com/guide/topics/manifest/permission-element.html.
<activity android:name=“.Login” android:label=“@string/app_name” android:launchMode=“standard” android:screenOrientation=“portrait” android:permission= “com.wiley.fordummies.androidsdk.tictactoe.LAUNCHACTIVITY” >
<uses-permission android:name=“com.wiley.fordummies.androidsdk.tictactoe.LAUNCHACTIVITY”/>
This request is needed by the package in which the activity itself is located. Any separate package that has applications that will invoke the Login activity must (obviously) also request this permission.
The Android framework also uses a permissions-based scheme to protect content providers. Note that the Tic-Tac-Toe application must declare the need for the following permission to be able to read information about your contacts (and send them your scores):
<uses-permission android:name=“android.permission.READ_CONTACTS”/>
Finally, we give you some techniques in the remainder of this section to help you debug permission errors.
If an application fails because of a permission error, you see an entry like the following in the logcat window (it's one long line, but we indented it here to improve readability):
02-28 12:48:00.864: ERROR/AndroidRuntime(378): java.lang.SecurityException: Permission Denial: starting Intent { act=com.wiley.fordummies.androidsdk.tictactoe.Login cmp=com.wiley.fordummies.androidsdk.tictactoe/.Login } from ProcessRecord{407740c0 378:com.wiley.fordummies.androidsdk.tictactoe/10033} (pid=378, uid=10033) requires com.wiley.fordummies.androidsdk.tictactoe.permission.LAUNCHACTIVITY
The key string in this example is, of course, java.lang.Security Exception. The following lines (also from logcat) indicate that the exception is being thrown from the SplashScreen activity when it is trying to start the Login activity:
02-28 21:04:39.758: ERROR/AndroidRuntime(914):at com.wiley.fordummies.androidsdk.tictactoe.SplashScreen$1.run (SplashScreen.java:36)
You use the next technique to install the .apk on either an emulator or a device, find the directory by using the adb executable supplied with your Android distribution, and open a shell, cmd, or terminal window in that directory. Type this line:
./adb shell pm list permissions
You will see the text shown below, with your custom permission (LAUNCHACTIVITY) nestling in it:
permission:android.permission.INTERNAL_SYSTEM_WINDOW permission:android.permission.MOVE_PACKAGE permission:android.permission.READ_INPUT_STATE permission:com.google.android.providers.settings.permission.READ_GSETTINGS permission:android.permission.REBOOT permission:android.permission.STATUS_BAR permission:android.permission.ACCESS_DOWNLOAD_MANAGER_ADVANCED permission:android.permission.STOP_APP_SWITCHES permission:android.permission.MANAGE_APP_TOKENS … permission:com.wiley.fordummies.androidsdk.tictactoe.LAUNCHACTIVITY … permission:android.permission.SET_ACTIVITY_WATCHER permission:android.permission.BACKUP permission:android.permission.SET_TIME permission:android.permission.STATUS_BAR_SERVICE permission:android.permission.PERFORM_CDMA_PROVISIONING permission:android.permission.INSTALL_PACKAGES permission:com.google.android.apps.maps.permission.C2D_MESSAGE permission:android.permission.CALL_PRIVILEGED permission:android.permission.CHANGE_COMPONENT_ENABLED_STATE permission:android.permission.WRITE_GSERVICES permission:android.permission.BIND_WALLPAPER
Finally, we show you what happens if you put your permission entry in the wrong place. The following lines are shown in logcat if the LAUNCHACTIVITY permission declaration is at the wrong level (for example, inside the activity element):
02-28 16:53:09.838: DEBUG/PackageManager(77): Permissions: com.wiley. fordummies.androidsdk.tictactoe.LAUNCHACTIVITY 02-28 17:04:18.888: WARN/PackageParser(77): Unknown element under <application>: permission at /data/app/vmdl1654102309.tmp Binary XML file line #11 02-28 17:04:20.438: WARN/PackageManager(77): Unknown permission com.wiley. fordummies.androidsdk.tictactoe.LAUNCHACTIVITY inpackage com.wiley.fordummies.androidsdk.tictactoe
The primary security concern created by using SQLite databases is the SQL injection attack, in which the attacker is able to force the system to execute his own query and return data that he does not have authorization to access. Suppose that in response to aprompt for a person's name, you enter Bob on the form and the application returns Bob's e-mail address by looking up a table using this query:
Select e-mail from user_information where name = Bob
Before software developers understood SQL injection attacks, they (the software developers) would use string concatenation to create queries. Thus, for the example shown above, a string was programmatically created that looked exactly like the query shown in the preceding example. This string was then sent to the database to execute.
But note what happens if you enter Bob; select table_names from user_tables in the entry field of the user interface: The query string becomes
Select e-mail from user_information where name = Bob; select table_names from user_tables
Most SQL databases would execute both queries, returning not only Bob's e-mail but also the names of the programmer-defined tables in the system. (The user_tables view is standard in most databases that contain the names of all user-defined tables.) Armed with this information, an attacker can inject all kinds of queries into a database to read all the other tables — even the system tables.
Defending against this type of attack is a straightforward process. The trick is to use what are known as “bind” variables. We do this in the Tic-Tac-Toe application. Look at the following lines that were extracted from the file DatabaseHelper.java:
private static final String TABLE_NAME = “Accounts”; … private static final String INSERT = “insert into ” + TABLE_NAME + “(name,password) values (?, ?)” ; … public DatabaseHelper(Context context) { … this.insertStmt = this.db.compileStatement(INSERT); … } … public long insert(String name, Stringpassword) { this.insertStmt.bindString(1, name); this.insertStmt.bindString(2,password); return this.insertStmt.executeInsert(); }
The constant INSERT defines a template for the database query, where the two question marks (?) define locations where data can be inserted. The this.insertStmt = this.db.compileStatement(INSERT) statement is compiling the query into an internal data structure, and the insert(…) method assembles the query from the parameters that are sent to it. If someone attempted the SQL injection attack from the preceding example (and added a query to the Password field), the query would look like the following line, which creates an odd password but does nothing harmful:
insert into Accounts (name,password) values (‘Bob’, ‘<password>; select table_ names from user_tables’)
After you know how the Android security model works, we have to tell how to leverage it for security purposes. To begin with, follow the principle of least privilege and give your app the least possible level of capability so that if someone uses it in an unauthorized manner, the least amount of damage will be done. If your app needs only a coarse location (at the city level), for example, don't give it fine location capability. If your app doesn't need to save external files, don't write it so that it can save them. If your app doesn't need complete access to a content provider, give it access only to the Universal Resource Identifiers (URI) it needs.
You should also limit your app's accessibility with respect to other applications (those not developed by you). If certain activities in your app are security risks and are not to be started by other activities, declare custom permissions for these activities. Then if a malicious app wants to use your app, it must declare its true intentions by requesting these custom permissions. The user then has a chance to realize this malicious intent and refuse to accept the request.
Before we end this section, and so as to connect it with the security categories we covered in the earlier section, note that the above are mitigation tactics — they help you minimize the damage caused by a breach.
The appropriate use of permissions can go a long way toward helping to make your apps secure. The following list describes some additional steps you can take to make your applications more secure (the categories the strategy belongs to are shown in parentheses):
3.12.136.186