How to Code Android Applications With Security In Mind

165

Android is a great platform, but as with any platform, careless coding can introduce security risks into your apps. Read on for some tips and best practices to make your apps secure and your users happy.

PadlockOne of the big ways that Android provides built-in security is by giving each app its own sandbox and its own independent process. They have limited interaction with the OS, and no interaction with one another. Android provides inter-process communication methods, and a permissions system, both discussed below; work with these rather than around them, to avoid introducing your very own security holes.

Limit permissions

If your app wants to do certain things (for example, use the camera, or access external storage — more on this in a moment), Android requires you to explicitly set a permission in your AndroidManifest.xml file. Where possible, it’s best to design your app to minimize the number of permissions you need. Not only is it better security, but it makes users happier (asking for loads of permissions can result in negative reviews).

It’s also possible to create new permissions specific to your app, but it’s best to avoid this if you can.

Data storage security

There are two basic options for data storage: internal storage or external storage. By default, anything you write on internal storage is accessible only to your app. You can change this by explicitly changing the mode to MODE_WORLD_READABLE or MODE_WORLD_WRITABLE, but that automatically reduces your app’s security so think very carefully before you do this.

If you want to share data (saving photos, for example), you can use external storage, which is globally read/writable. Again, think carefully about what you save externally. Never save sensitive data or executable data externally, and never load sensitive or executable data from external storage. While we’re at it, never load executable data from the network, either.

Use Content Providers — Carefully

A third option if you want to share data with other apps is to use a content provider. These provide structured data storage and managed access. Android itself has some content providers for managing audio, video, images, and contact information. You may also want to write your own content provider if you need to copy/paste complicated data from your app to other apps. See the Android Content Provider document for more details.

To avoid allowing other apps to access your ContentProvider, set it as android:exported=false in your app’s AndroidManifest.xml. Otherwise, set this value to true. Check out the details of the available manifest permissions carefully if you’re allowing access, and allow only the access you definitely need right now. It’s easier to add more permissions later than it is to take some away. If it’s only one of your own apps that needs the access, you can set the protection level to “signature”. This means that any app released with the same signature (yours!) has access, but other apps don’t. This is automatic, not requiring user approval, so provides a smoother user experience.

When using content providers (or SQL databases more generally), you need to be careful to avoid malicious SQL injection. Use the Android-provided query()update(), and delete()methods instead of writing your own SQL. However, if you’re building queries from user-provided data, you’ll still need to be careful to check that before you do anything with it, or your user-provided data could be an attempt at malicious SQL injection.

Secure networking

If you want to share information between apps, it can be tempting to roll your own way of communicating, using network sockets or other Linux traditional methods. This raises security issues. Instead, use the Android IPC (inter-process communication) methods: Intent, Binder, Messenger, BroadcastReceiver, and so on. However, do also bear in mind that these by their nature are public. If you’re handling data from one of these (or from any other public API), make sure you check it before just using it in your app, to avoid a malicious app masquerading as something you’re expecting and passing malicious data into your app.

If you want to execute a delayed action elsewhere in the system, look into using PendingIntent. PendingIntent is a ‘token’ that is passed to and from app A to app B, allowing app B to execute an action on behalf of app A at some future time. PendingIntent requires a specific Context to be provided (which should be that of your base app, app A) and will be executed only with the permissions of that Context.

Finally, use HTTPS rather than HTTP where possible, and certainly for any sensitive data — remember that mobile devices are often used on insecure wifi networks. And don’t use SMS services (which are inherently insecure) to transfer sensitive data, or indeed any data at all unless SMS integration is a deliberate feature of your app.

Take care when using WebView

A WebView allows an app to display a webpage without sending the user off to a full mobile browser like Chrome. By default, Javascript and Plugins are disabled. It’s possible to turn them on, but do this only if you absolutely must, as they are a security risk. If you do turn JS on, use HTTPS if you can. You should also disable local file access, to limit the damage which any attack could do

If you do need to turn on some of the above options, consider creating a WebViewClient subclass, and overriding shouldOverrideUrlLoading and shouldInterceptRequest, to intercept and inspect any URL resource requests from within a WebView. (You might, for example, pass any such requests on to a full mobile browser; so your app would show the user a single page but send any further clicks to a browser.) See this helpful resource, Adventures with Android WebViews, for more information on WebViews and security.

Check data input

As mentioned above, if you’re loading input from any public API (BroadcastReceiver, Activity, any ContentProvider), check it in your app before you do anything with it. Malicious apps might provide fake data intended to gain access to your app’s internal workings. Sanity-checking is also good for avoiding unexpected bugs, so it’s worthwhile all round.

Cryptography

If you want to encrypt your data to increase its security, go right ahead. But don’t use your own home-rolled encryption; use one of the existing libraries that works on Android, such as the implementations in javax.crypto.Cipher. They’ve had more eyeballs over them and are in wider use, so there’s a higher likelihood of any bugs being spotted. When generating a key, use a secure random number system like SecureRandom. There’s more information on the correct use of SecureRandom and other cryptography issues in this blogpost.

A few simple steps and a basic awareness of security can significantly decrease the chances of a security problem with your app. However, if you’re dealing with really sensitive data, you should make sure you research the subject fully and test carefully before releasing your app into the wild.