Friday, November 18, 2011

Android: Protect ContentProvider with signature

I have been looking for secure ways for my Android apps to share data, and was looking into permissions. In particular, the signature level in android:protectionLevel looks really promising:

A permission that the system grants only if the requesting application is signed with the same certificate as the application that declared the permission. If the certificates match, the system automatically grants the permission without notifying the user or asking for the user's explicit approval.

The idea is to have a main app for displaying data, and multiple modules supplying the data. Permissions only work with one of the four application components: Activity, Service, ContentProvider, and BroadcastReceiver. ContentProvider is the logical choice for serving data.

Loading sqlite database from resource

It is a bit of a pain to write a ContentProvider, though. Since all I wanted was to test the permissions, I took a shortcut: I followed this tutorial and loaded a sqlite database from resource. To automate the database creation, I wrote a script to load the data from a tab-delimited file.

Permission setup

It took me many tries to get the permissions right. I know that the <provider> need to request the permission, but where do I declare it? I tried both in the module and the main app, but no luck, the main app could use the ContentProvider no matter how I signed the apps. Turns out it was a stupid error: I declared the permission with the <provider>, inside of the <application> block. It should go outside!

So the formula looks like this:

  • Declare the permission in the provider app
  • Request the permission in the provider app
  • Use the permission in the consumer app

When everything was setup properly, it was very satisfying to see my app throwing java.lang.SecurityException when I sign it with a non-matching certificate.

The code

I uploaded some sample code to github: Hope you found it useful!

1 comment:

Inline coding questions will not be answsered. Instead, ask on StackOverflow and put the link in the comment.

  1. After some experimentation, the following holds true for apps signed with the same certificate:
    1. consuming apps can access data without this permission if they use the same shared user id as the content providing app.
    2. If a consuming app chooses not to use the shared user id of the content providing app it can still access data by using the permission.