Security of critical data passing between activities via intent extras - android

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.

Related

Content Provider vs SharedUserId vs Global Process for sharing data across applications

I found three ways to share data across applications.
1.Content Provider
2.SharedUserId-When you declare the same shared user id for more than one application, they can reach each other's resources (data fields, views, etc.). provided applications are signed with same certificate.
3.Global Process-Put a component of one application in separate process by using android:process attribute and naming process starting with lowercase letter and another component of another appication in separate process with same name as the separate process of first application.Now these components can share data.
I am confused what to use when or which is more efficient?
I found three ways to share data across applications.
#2 and #3 are the same, insofar as #3 (shared process) requires #2 (sharedUserId).
You also missed all other forms of standard Android IPC, including:
starting activities
starting services
binding to services
sending broadcasts
I am confused what to use when
Ordinary app developers should use #1 (ContentProvider) or one of the other standard Android IPC mechanisms that I outlined above. You have no control over when users update apps, and using formal IPC enforces a clear separation between the apps, forcing you to think through things like API contracts, API versioning, and related concerns.
sharedUserId and shared processes are really there for device manufacturers, where apps are pre-installed and then updated in unison via a firmware update. Personally, I recommend to device manufacturers that they too use standard IPC, for most scenarios. For example, if App A modifies App B's files directly, how does App B find out? What if App B then overwrites App A's changes, because App B did not know about those changes? In many other areas of computer programming, we have gotten away from having multiple processes from multiple apps work with each others files directly.
which is more efficient?
Efficiency should not be an issue in this case, as you should be using any of these techniques infrequently. If you have two apps that need to communicate with each other frequently, then you really have one app, and you should implement it that way.

Is data transfer between Android applications secure?

I can call other apps' Activities without problem, including sending them some data and receiving some data back. But I am sending and receiving some sensitive information that could arguably be misused if in the wrong hands. My question is, is this data safe when traveling between appications?
For example, I call an Activity like this:
Intent intent = new Intent("com.my.package.MY_REQUEST_ACTION");
intent.setClassName("com.other.package", "com.other.package.UserActionActivity");
signerIntent.putExtra("INTENT_PASSWORD", "1234");
signerIntent.putExtra("INTENT_COMMAND", "COMMAND_DO_SOMETHING");
signerIntent.setType("text/plain");
startActivityForResult(intent, 0);
And return something in UserActionActivity:
Intent result = new Intent("com.other.package.INTENT_RESULT_DESCRIPTION");
result.putExtra("INTENT_RETURN_RESULT", "...");
result.putExtra("INTENT_RETURN_RESULT2", "...");
setResult(Activity.RESULT_OK, result);
finish();
And so on. But how secure are these extra strings? Do I have to worry about them being accessible to other applications (other than the two involved), either intentionally or through some kind of "hack"? Do I need something like public key encryption?
And is the situation different on rooted systems (i.e. an app with root privileges can, without too much effort, read inter-app communication)?
Do I have to worry about them being accessible to other applications (other than the two involved), either intentionally or through some kind of "hack"?
Let's assume for the moment that neither app has been modified by an attacker.
If so, then in principle, the communications that you have established should be private on non-rooted device. In practice, there have been bugs with activity Intent extras, though none that I know of recently. Of your IPC options, activities are probably the worst choice from a security standpoint, as they have other impacts (e.g., appear in the overview/recent-tasks screen) that increase the likelihood that there is some bug that we have overlooked.
In your code, though, both sides assume that the other app has not been modified. In particular:
Unless you have some security that is not shown, any app on the device can run the code in your first snippet and try to trick the app to return the response in the second snippet.
The code in your first snippet assumes that com.other.package has not been modified by an attacker.
There are ways to help defend against this (e.g., custom signature permissions, checking the signature at runtime).
Also, bear in mind that an attacker can find "1234" without much difficulty.
With regards to the comments advising encryption, given the protocol that you are describing, encryption seems like an unlikely solution. If you have to provide a secret (INTENT_PASSWORD) in the IPC protocol, then there is no shared secret that both apps would have to use for encryption purposes, and I'm not quite certain what public-key infrastructure you would use to offer public-key encryption here.
And is the situation different on rooted systems (i.e. an app with root privileges can, without too much effort, read inter-app communication)?
Absolutely. On a rooted device, all bets are off. That is not tied specifically to IPC, though.
short answer: it is not safe but it needs some effort for the attacker.
long answer:
the transfer can be intercepted by a man in the middle attack:
on unrooted phones:
if you send data to intent.setClassName("com.other.package", "com.other.package.UserActionActivity"); somone can uninstall the original "com.other.package" and install his own "com.other.package" with the same activity that receives the unencrypted data.
For example an attacker can disassemble the original software, add code (that does something with the secret data) and reassemble the code to a new apk (with a different certificate)
On rooted devices: I donot know but i assume it is possible that the "exposed framework" is capable to intercept and redefine android os calls.

How can I securely transmit data between applications

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).

Security of sending sensitive intent extras within my own app?

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.

LocalBroadcastManager a number of advantages?

Has anyone really used this? I am so in the habit of registering/unregistering my BroadcastReceivers inside an Activity that I almost stuttered when I saw this. Does this keep all my Broadcasts to my specific Linux Process ID that my app is running on? My Actions and Extras are package specific and the ones that are not are meant to be that way to allow other applications to possibly pick up an intent. I can see one easy use, I just did a test case with an AsyncTask, ProgressDialog, and an Activity. But what is the purpose? Is this for security? I am not a linux guru and was hoping for some input.
Per the LocalBroadcastManager documentation, the advantages are:
You know that the data you are broadcasting won't leave your app, so don't need to worry about leaking private data.
It is not possible for other applications to send these broadcasts to your app, so you don't need to worry about having security holes they can exploit.
It is more efficient than sending a global broadcast through the system.
You can also take a look at the LocalBroadcastManager source if you'd like to determine exactly how it works.

Categories

Resources