- Android Development: Database Upgrades
- Android Development: Missing API
- (Not) Integrating Application with Intents
- Android Activity Lifecycle
- URI Matching in Android’s IntentFilters
- Android Intent Sender Verification
- Android Jittery Scrolling Gallery
- Encryption on Android & BouncyCastle
- Android Permission Handling
- ContentProvider Curses Cursor
- ContentProvider Wasted Potential
Following up on the Intent theme from the previous post, here’s another tidbit about Intents: apparently you cannot reliably tell where an Intent is being sent from.
Intents can be launched in various ways:
- Intents can be broadcast to any receiver.
- Intents can be fired off to a particular receiver, and results will be ignored.
- Intents can be fired off to a particular receiver, and the sender gets notified of results.
All three methods have their place. What’s striking is that Intents carry information about the receiver, the action, and tons of optional metadata — but they don’t seem to carry any sender information. As an application developer, then, you have to trust Intents more or less blindly.
I should note that if the sender expects results, then one can find out what that sender is — there’s a function called getCallingPackage() for that. But that function has two major drawbacks:
- It’s part of the
Activityclass, which means senders for broadcast Intents can’t be detected. - It returns
nullif the sender does not expect a result.
All of which means that, unfortunately, if your Intent is supposed to do something sensitive, there’s no easy way for you to ensure the Intent is not malicious.
Imagine you were to define an Intent that sent your own contact card as a vCard via Bluetooth. A malicious app could fire off that Intent periodically, and a second app could be used to sniff such transfers. Spend enough time on the tube, and you can harvest a fair amount of data1. Clearly security should be built into this Intent system in Android.
There are a few things you can do to deal with the problem; unfortunately, none of them are pretty.
- You can always ask for confirmation before executing whatever the Intent requests. That’s easy enough to do for non-broadcast Intents, at any rate.
- You can count Intents received per time unit, and if they’re always the same, start ignoring them — but better ask the user before doing so, just in case they’re legitimate.
- You can hack up some authentication protocol.
That last suggestion can get tricky. It all hinges on the fact that while you can’t determine an Intent sender, you can verify if an Intent sender is who they claim they are.
Before I go into that, though, let me quickly state that I might be missing an API that would make the following simpler. I’ve looked before, though, and haven’t found anything, so I’m somewhat certain I’m not.
The first thing you pretty much have to do is require that an Intent sender sends their package name as an Intent extra — that alone might be a hurdle for some Intents, so this solution may not be universally applicable. But if you can require that, it’s a start.
Of course any malicious app could send innocent looking package names instead, so we’ll need to verify they’re telling the truth. Unless the Intent is sent from the same process, Binder‘s getCallingUid() should get you the user ID of the calling process.
You can also get the process ID, but unfortunately that doesn’t seem to be resolvable to a package name. However, PackageManager then lets you list all allowed package names for the given UID. At the first level of verification, you can at least ensure that a malicious app is using the same UID as the package they claim to be. With that, you’re pretty much at the point of trusting vendors, rather than apps.
To get to the point of trusting an app, you can now browse the app’s claimed package information until you find a Service or ContentProvider with a pre-defined name of your choosing that the package author must implement. Bind to that, and perform a key exchange handshake via a series of API calls, which will probably be similar in content and the steps performed as the handshake in handshake in TLS.
Following the handshake, the apps can exchange a session-specific token that is attached to all further Intents being sent. This token at least, but probably all Intent data, is signed by the sender and encrypted with the recipients public key. That’ll ensure that only the recipient knows what the Intent data is2, but also that the recipient can find out who the sender is by mapping the token back to the package it contacted for the key exchange.
I told you it’s not pretty, didn’t I?
- Yes, it’s a bit random, but the concept can be refined. [↩]
- Which may be beyond the scope of authenticating an app; just drop the encryption part if you don’t care. [↩]


