Want to keep learning?

This content is taken from the University of Southampton's online course, Secure Android App Development. Join the course to learn more.

Securely sharing data via Content Providers

If your app is intended to share data with other apps then you should use a Content Provider to do so. This is the mechanism specifically provided within Android for this purpose.

The Android documentation provides a good introduction to Content Providers.

To secure a Content Provider you need to do two things:

  1. Control access to the Content Provider through Android permissions. This was covered in week 3.

  2. Guard against SQL injection for Content Providers that wrap SQLite databases (or any other database that supports SQL).

The parameterised methods provided by a Content Provider: query(), insert(), update(), and delete(), help guard against SQL injection.

However, we do need to pay attention to the projection and selection clauses passed to these methods, as carelessness here could result in SQL injection.

Where should the security barrier be?

There are two approaches we could take:

  1. The implementation of the query(), update(), and delete() methods within the Content Provider could try to catch SQL injection attempts.

  2. The caller of the query(), update(), and delete() methods within the client apps can block SQL injection attempts.

The choice depends upon where the threat is coming from. The first method puts the security barrier within the Content Provider, whereas the second method puts the security barrier within the clients of the Content Provider.

If the Content Provider is accessible by any app, or any app that the user grants permission to, then the security barrier needs to be within the Content Provider itself.

However, if access to the Content Provider is restricted to apps you know you can trust, then moving the security barrier into the client apps might make sense.

The technical stuff

At the technical level the solution is the same, the only difference is where the defensive code is placed: in the Content Provider, or in the calling app.

The key idea is the same as the one we saw in week 2 where we used parameterised queries to block SQL injection.

Inside the Content Provider the call to the query() method will result in a corresponding query call on the database itself.

We need to ensure that the only user input that reaches that inner query is passed in the selectionArgs array (of the inner call), with corresponding placeholders (parameters) in the actual SQL command.

The SQL command MUST NOT directly include any user input.

Our code can use the user input to select from a predefined hard-coded list of SQL commands, but not use the user input to construct the SQL command.

The Content Provider’s query() method has the following signature.

Cursor query (Uri uri, 
                String[] projection, 
                String selection, 
                String[] selectionArgs, 
                String sortOrder)

If we place the security barrier within the Content Provider we need to ensure that the projection and selection parameters are not passed directly to the inner database query.

Alternatively, if we place the security barrier in the calling app, then the parameters projection and selection must not be directly constructed from user input.

Share this article:

This article is from the free online course:

Secure Android App Development

University of Southampton