I want to transmit a small amount of data between a Service and an Activity. These are separate applications. Ideally, I'd just pack my data (and a nonce for confirmation) into an Intent and use that. But per Mark Murphy's blog post Warning: Activity Intent Extras Can Be Public I know this is not safe.
Is ResultReceiver safe?
Is there a better way to do what I want?
Here is my use case:
Service A is going to launch Activity B with an Intent and ask the question "Is operation X authorized?". User action may be required, so that's why I'm launching an Activity from a Service.
I want Activity B to answer simply "yes" or "no". I want to make sure a malicious app on the device can't spoof that response. My current code uses an Intent to send the response.
I'm taking a defense-in-depth approach, and part of that is that I don't want the request from A to B to be readable by anybody else. Among other things, I intend to pack a nonce into the original request
Answering #mwhs' questions:
Service is only asking a yes/no question. I want to be very sure that the response comes from who I'm expecting it from. A nonce should do the trick, but it would need to be transmitted securely.
I'm not a security expert other than a little dabbling. What do you mean by "receipt of that very nonce on the initial sender side must carry a proof, that the intended party actually replied with that nonce, ideally by binding the nonce (or a decrement of it) cryptographically to a proof of identity (which can be usage of a shared good key for instance)"?
Assuming I can get the nonce securely to the other party, doesn't the fact that the other party responds with it constitute proof that they're the intended party? How do I "bind" the nonce to proof of identity? Some sort of HMAC? And why decrement it; is that some sort of hash-buster?
I'm a little leery of embedding shared secrets into an app that could theoretically be reverse-engineered.
Service A is going to launch Activity B with an Intent and ask the question "Is operation X authorized?". User action may be required, so that's why I'm launching an Activity from a Service.
For ordinary apps on ordinary devices, this is not a recommended approach, unless you are damn sure that the user won't regret you taking over the foreground with your activity.
I want Activity B to answer simply "yes" or "no". I want to make sure a malicious app on the device can't spoof that response.
The blog post that you cite refers to a bug that used to exist in Android, for extras packaged on an Intent used for startActivity(). Your scenario, as described, does not involve this, as you did not mention any extras on the Intent passed from Service A to Activity B. Plus, that bug has since been fixed, though I forget exactly where in the 4.x series it was fixed.
My current code uses an Intent to send the response.
That's not a particularly informative statement. That's akin to saying that you use a string to send the response. A string or an Intent may be the format of the response, but somehow you need to use inter-process communication (IPC) to get that response back to Service A.
One non-option is startActivityForResult(), as that is only available to activities, not services.
Possible IPC options include:
Calling startService() on the service, passing the Intent, using a custom signature permission to ensure that only your apps can call startService() on that service.
Calling bindService() on the service, waiting to get the binder, then passing the Intent (or whatever) to some method that you implement on the Binder (and using the same custom signature permission as above).
Passing a PendingIntent from Service A to Activity B as an extra, and having Activity B fill and execute that PendingIntent. You would use a signature permission or validating the signing key of Activity B's app to ensure that Service A only sends this to the correct app. And, you'd need to research the exact point when the problem that I outlined in the blog post got fixed.
Passing a ResultReceiver from Service A to Activity B (which otherwise works much as would the PendingIntent scenario above)
Having Service A register a BroadcastReceiver via registerReceiver(), then have Activity B send a broadcast matching the receiver's IntentFilter. You would need to go the custom signature permission route.
Doing something outside the Android component system (e.g., using an HTTP daemon in the service that the activity talks to). Ick.
Note that custom permissions suck, at least before Android 5.0.
Other than the now-fixed recent-activities Intent leak, I am not aware of any current means for spying on IPC, except:
rooted devices
custom ROMs
impersonation (e.g., Service A talks to Activity M from a malware author that is masquerading as Activity B)
The latter scenario is where signature permissions or validating the signing key of Activity B's app come into play.
Anything that is exported (scenarios #1, #2, #5) is at risk of spoofing. signature permissions help, except that custom permissions suck. I would lean towards #3 or #4.
Depending on what other communications are going on between these apps, there may be other options (e.g., long-term bound service, with callback objects to provide bi-directional communication).
Related
I wonder if it is a bad idea to pass critical data between application's activities via intent extras.
For example, assume an application have 2 activities: A and B. Activity B will be started by A and A passes some critical information such as password via an intent extra when starting B.
I wonder if this is a dangerous or bad practice in android. For example, can such an approach leak password to other apps? Is there any better way to do so? Generally, do you know any good reference for learning about bad practices in android coding?
Assuming that you're referring to intents that just start specific Activities, I think you don't need to worry too much.
To take advantage of sensitive information in such intents, attacker will need to do at least one of the following:
Find a bug in Android framework that can be exploited
Upload custom ROM with malicious additions to user's device without user noticing
Upload application APK with malicious additions to user's device without user noticing
While all these scenarios can theoretically happen, I wouldn't bother to safe-guard against them in most cases.
I have an activity which asks for a username and password, then starts another activity in my app to complete a user signup. I want to send the username+password as intent extras to the second activity. Something like:
Intent intent = new Intent(activity, SecondActivity.class);
intent.putExtra("u", username);
intent.putExtra("p", password);
startActivity(intent);
and my manifest defines SecondActivity like:
<activity
android:name="com.me.SecondActivity"
android:label="">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.me.FirstActivity" />
</activity>
and now I'm having doubts about the security of sending the username+password as intent extras like this - is it possible for another app to intercept the invocation of SecondActivity with a spoofed intent filter? Besides that, I wonder what happens with the intent extras, are they ever persisted to disk by the OS? Someone might be able to look at them there if so.
Thanks
The key here is the distinction between Implicit Intents and Explicit Intents. Your example uses an Explicit Intent as your are specifying the exact class your want to run. This is fine, because Explicit Intents cannot be intercepted and will stay within your application.
Implicit Intents however, open up several possible attack vectors. This article talks about it in more detail. I would very much recommend against using Implicit Intents to pass any kind of sensitive information.
From the Android Docs:
Explicit Intents have specified a component (via setComponent(ComponentName) or setClass(Context, Class)), which provides the exact class to be run.
Implicit Intents have not specified a component; instead, they must include enough information for the system to determine which of the available components is best to run for that intent.
As I stated, for your example in the question, passing the password via Intent is relatively secure in that no other application can intercept it at runtime. But it is important to note that this is not always the case, and using implicit Intents could theoretically allow Intent Interception and expose the sensitive information.
Edit:
As for persisting the Intent Extras to the disk, yes this is a risk. Keep in mind however, that if someone has root access on the device and is using it to try to search the disk for this persisted intent information, there may be easier ways for them to get the same information. No matter what you do, someone with root access to the physical device will probably be able to get that password off unless you do some very excellent encryption.
My recommendation on a overall security perspective is to try not to deal with passwords directly in any kind of long term or persistent context. Passwords should only be used during a log in process and discarded immediately afterwards (assuming you are authenticating with a server). Therefore, with the normal use of the application (a legitimate user with a real password), you don't have to worry about a malicious actor inspecting the device memory, because by the time the malicious actor gets a hold of the device, the password has long sense been removed from memory.
It is possible for third-party apps to intercept system-wide intents. I suggest encrypting your data before sending it to the next intent, and then decrypting it once it has been received.
Handling passwords should always be a very short term affair. It's recommended to use them only for authentication request and then discard them. Coming to specifics of your question, i.e., sending password between activities through an explicit intent, this is secure to the extent that no other app will be able to intercept it and view the value. However, the passwords value needs to be maintained somewhere (memory or disk) in order to pass it to your secondary activity. If it's maintained on the disk it's pretty easy to retrieve. If its maintained in memory, an attacker who gets access to your device can root it and then perform memory dump to view the values in the memory. Thus it is not recommended to deal with passwords in this fashion.
What would be good approach to establish communication between different APKs? One app can send request to other apps and wait for response.
I can think of:
1. using BroadCast receivers: send "request" broadcast and receive returned broadcasts (results). This seems nice clean solution, no security problems, but how to get all results back as "one" - usually I will want to send out broadcast to collect app identifications, and get result like array.
2. use sharedUserId between all these apps and gather or execute whatever I need directly on the apps. But here are have couple of more loose ends:
- how do I get list of apps (through list of installed packages?)
- is with sharedUserId and same signature possible to access other app internals? like register/unregister component, etc.?
Thanks!
EDIT:
Have been reading more about ordered broadcasts and so far this seems good way to go. Using order broadcast each of other apps will fill in its own data part and result will be returned back to supplied "final" receiver.
I am using ordered broadcasts. When broadcast is send out, each receiver adds its information and last receiver calls resultReceiver.
So I'm working on a service that will handle requests to send data to a socket.
I've done socket programming in a service before, but only within the same application. I'd like this to just sit and do nothing until any application wants to give it data to send. That's all well and good.
I have register an intent filter and the usual stuff and can process the data. But I want to process the data coming from different activities in different threads (subsequent calls from the same application will be computed on the same thread).
Is there a way to get the calling package or app or whatever? I'd prefer not to require passing in an identifier as an extra to prevent spoofing. (It's not a serious security concern, it's just each application needs its data processed in the order that it's received.)
I had run to the same issue in the past. I couldn't find a way to know how send the intent and I ended up adding an extra.
If you don't want to use an extra perhaps you might want to set an Action but it's almost the same thing.
Is there a significant difference in time needed for sending data over a service or by using an intent?
Are there general advices when to use service and when to use intents?
These are two completely different things. The question isn't which is faster, but what you are trying to do.
If you want to transfer data from one activity to another, you pass it through the intent. If this is not sufficient for you (too much data for example), you can take other approaches but they will not involve a Service. For example, you may have a singleton holding your shared data, which both activities access... but be extremely careful about your process being killed at various points which causes the singleton to go away (and using a Service for this won't let you get away with not dealing with such a situation).
A Service is to do some work in the background even if the user isn't directly interacting with the app. Especially if we are talking about stuff within one .apk (and thus typically one process), there are very few other reasons to use a Service.
It depends of what you need.
Intent is preferable if you can. You will be able to send primitives from an activity to an other, and using startActivityForResult() you'll get an intent back to the caller Activity.
Service is for data processing in the background and can be very CPU/Memory consuming. With a Service, you have to create an interface between your Activity and the Service, so you can call basic methods of the Service directly from the Activity, you can control the service from the Activity.
This is really not the same purpose. Read documentation about Intents and the information you can Bundle in it, that's probably what you need.
When you want to pass data from your current activity to a new activity, the best is to pass a Bundle along with your Intent. It is used to pass on "acquired" user data.
Services run in the background while another activity is still in the foreground. "Background" doesn't mean that it doesn't display - most services have a graphic visualisation of some sort - it means that it isn't part of the activities stack. For example, your Activity may be sending a text message and your Service may be a soft keyboard. Services can communicate with activities - in this instance, your keyboard of course needs to send the characters to the text message Activity - but it often involves using a rather complex interface. It is used for collecting and passing on "live" user data to an Activity.
Many methods to pass data between activities. See here for tips on a way to choose.