3

I am trying to implement some alarm scheduling by using AlarmManager. Since when a alarm is triggered, I want to use a WakefulBroadcastReceiver which starts an IntentService to do some background job.

I have some questions related to security/privacy of the parameters passed for alarm's intents.

  1. When setting a PendingIntent for a alarm I do something like:

    Intent myIntent = new Intent(context, MyReceiver.class);        
    myIntent.putExtra("test", "testValue");
    Bundle bundle = new Bundle();
    bundle.putParcelable("bundleValue", bundleTestValue2);
    myIntent.putExtra("test3", bundle);
    PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 323,
        myIntent, PendingIntent.FLAG_UPDATE_CURRENT);
    

My question is: how private are the values set as Extra for the pendingIntent of the alarm? Is there a chance of them getting read by some other app since is being used by Android Alarm's Manager after it is scheduled?

  1. By having a receiver like

    public class MyReceiver extends WakefulBroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
           startWakefulService(context, MyIntentService);
    }
    

And on android manifest

 <receiver
            android:name=".receivers.MyReceiver"
            android:exported="false"/>

 <service 
          android:name=".MyIntentService" 
          android:exported="false"/>

And the service

public class MyIntentService extends IntentService {

  @Override
  protected void onHandleIntent(Intent intent) {

     try {
          //logic here
     } catch{
     } finaly{
          MyReceiver.completeWakefulIntent(intent);
     } 
}

Call from within my Activity

sendBroadcast(new Intent(context, MyReceiver.class).putExtra(...);

Schedule a pending intent from an alarm

Intent myIntent = new Intent(context, MyReceiver.class);        
myIntent.putExtra("test", "testValue");

PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 323,
    myIntent, PendingIntent.FLAG_UPDATE_CURRENT);

how exposed is this receiver to other apps? Can it react to other apps except mine? Does this rise any security possible issues?

Thank you.

Later edit: Since the WakefullBroadcastReceiver seems the only way that guarantees that my service will get a partial wakelock, how can I make sure 100% that no other apps will be aware of my receiver and that my receiver won't get any other calls except ones made from my activity or from my set Alarm?

How would a WakefullBroadcastReceiver pattern works versus CommonsWare's WakefulIntentService ?

Later Edit: I've finally managed to finish my implementation.

  1. As stated before, both my WakefulBroadcastReceiver and IntentService are declared as exported="false" in my Android Manifest which from what I understand means that only my app can access them. Since the receiver is not exported, does it receive broadcasts from outside the app?

  2. When setting an alarm I use this PendingIntent:

    Intent myIntent = new Intent(context, MyReceiver.class);
    myIntent.putExtra("databaseId", "1"); PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 323, myIntent, PendingIntent.FLAG_UPDATE_CURRENT);

  3. When calling from my Activity I do:

sendBroadcast(new Intent(context, MyReceiver.class).putExtra("databaseId", "1"));

Is this enough?

Alin
  • 14,809
  • 40
  • 129
  • 218
  • 1
    Both `WakefulBroadcastReceiver` and `WakefulIntentService` use a combination of a `BroadcastReceiver` and an `IntentService`. With respect to your concerns, they are identical. – CommonsWare Jan 31 '17 at 11:53
  • @CommonsWare thank you very much for your time. Regarding the security of the `WakefullBroadcastReceiver` is there anything you could tell me? How can I make sure its `intent` does not get read by other apps or other apps interact with it by sending broadcasts to it? – Alin Jan 31 '17 at 12:00
  • 1
    You already have a lengthy answer on this subject. Vasily's opening sentence is a good one: "In general, I would say that it is an insecure practice to put sensitive data in Intent". Moreover, you should not need to put sensitive data in an `Intent`, where the `Intent` routes back to your own app. Use some identifier that is meaningless to outsiders but identifies how to load the data (e.g., primary key to a database table). – CommonsWare Jan 31 '17 at 12:09
  • @CommonsWare indeed, that's want I'm doing right now, using the primary keys in tables as extras. However I am still concerned if other apps are able to broadcast to my receiver or not... Or when I use in my activity `sendBroadcast` if my broadcast goes to other apps or not... – Alin Jan 31 '17 at 12:17
  • 1
    "However I am still concerned if other apps are able to broadcast to my receiver or not" -- any time you use a `PendingIntent`, you do not need that component to be exported, so third-party apps should not have access to your receiver. Any time that you work with one of your own components (e.g., calling `startService()` from the receiver), you do not need to export the component. So, you should not have a problem here. If you call `sendBroadcast()` with an explicit `Intent`, the broadcast only goes to that receiver; with an implicit `Intent`, the broadcast goes to all registered listeners. – CommonsWare Jan 31 '17 at 12:31
  • @CommonsWare The last phrase is `without an implicit Intent, the broadcast goes to all registered listenters`? I've added some code, both the `WakefullBroadcastReceiver` and the `IntentService` are `exported=false`. I've also added the way I am either preparing a `PendingIntent` from an `Alarm` or call `sendBroadcast` from the app's `Activity`. From what I understand, the `sendBroadcast` having declared intent, only goes to my receiver not others. Also the alarm having a PendingIntent also goes to my receiver. Having `exported=false` makes the receiver not available for other apps. Correct? – Alin Jan 31 '17 at 12:49
  • 1
    "the sendBroadcast having declared intent" -- I am unclear what this means. An explicit `Intent` is like `new Intent(this, YourReceiver.class)`. That will only go to `YourReceiver`. An implicit `Intent` is like `new Intent("your.custom.action.STRING")`. That goes to anyone choosing to listen to such broadcasts. For your use case, do not use an `` on the `` and use an explicit `Intent` for your broadcast. Or, do not use `sendBroadcast()`, but instead invoke your `IntentService` directly, for cases where it is not triggered by the alarm. – CommonsWare Jan 31 '17 at 13:01
  • @CommonsWare I want to use the receiver so that I don't need to hold wakelock in the service (`WakefullBroadcastReceiver` takes care of it), so that's why I am using the `sendBroadcast within my app`. I missed the explicit/implicit being different words, not that I've re-read carefully I understand. I send broadcast like `sendBroadcast(new Intent(context, MyReceiver.class).putExtra(...)` so that broadcast should only go on my Receiver directly and not to others. – Alin Jan 31 '17 at 13:08
  • @CommonsWare sorry to take your time, I've added a Later Edit please check to see if I understood correctly. Since I use `sendBroadcast` with an explicit `Intent` the broadcast should go only to my receiver. Same goes for `PendingIntent` in the case of the alarm. Having them not exported, should not be callable or listen from outside my app's process leaving no security threats. As a caution, I'm only passing some PK ids from the database as `Extras`. Did I understood right? – Alin Feb 16 '17 at 12:04
  • Why are you sending a broadcast to yourself? Use an event bus and keep it all in process, for faster processing and no security risk. For your `PendingIntent` scenario, what you propose seems fine. – CommonsWare Feb 16 '17 at 12:45
  • @CommonsWare Both the `PendingIntent` and the call from the `Activity` call the same `IntentService` meaning that it does the same things, only parameters may be different. I've used `sendBroadcast` within my activity to take advantage of the `wakelock` that the `WakefulBroadcastReceiver` handles by itself. So the app either called from Alarm or from itself, fires `BroadcastReceiver` which acquires wakelock while the `IntentService` is being executed. The call from the activity for instance, may take a few minutes, so I need to have a partial wakelock while IntentService is running... – Alin Feb 16 '17 at 16:06
  • I've decided to simply call the Service from the alarm. I've tested it and seems to work... I know there's no guarantee that he service will get a chance to requite the wakelock but it seems it does on my small testing amount. I'll do testing on more devices. – Alin Feb 17 '17 at 12:41

1 Answers1

3

Privacy considerations related to Intent extras

In general, I would say that it is an insecure practice to put sensitive data in Intent.

In theory, if Intent can only be consumed by specific application (discussed later) then only that application should be able to see its contents. However, given a vast amount of Android devices and OS versions (incl. rooted devices and custom ROMs), I wouldn't count on it.

You did not specify the kind of sensitive data you'd like to pass in Intent extras, therefore I can only give these general recommendations:

  1. Make sure you understand the "confidentiality level" of the data in question: is it secret, or just restricted? Or, maybe, it is public (in which case no protection needed)?
  2. Try to find another approach that doesn't involve passing sensitive data in Intent (I myself never encountered such a need).
  3. If you absolutely must pass sensitive data in Intent extras - consider encrypting it. The encryption model should be adequate to "confidentiality level" of the data, and to potential harm which could be done if that data is being intercepted (it can go all the way up to "server side" encryption).

Privacy/security considerations related to BroadcastReceiver

In general, BroadcastReceiver is a component which receives "system wide" broadcasts. The fact that the broadcasts are "system wide" should speak by itself about the level of privacy associated with them.

That being said, there is one mechanism by which developers can restrict broadcasts' scopes: custom permissions. Usage of custom permissions allows for two "levels of control" over broadcasts:

  1. If broadcast requires specific permission then only if BroadcastReceiver has that permission will it receive the broadcast.
  2. If BroadcastReceiver filters the incoming broadcasts by specific permissions, then only broadcasts carrying that permission will be delivered to that receiver.

While the above points can seem similar on the first sight, these are distinct schemes that can be used separately, or combined. The first scheme associates a broadcast with a permission (and the sender of that broadcast doesn't necessarily have that permission by himself), while the second scheme filters all broadcasts by specific permission (and the receiver must have that permission).

A better approach in your case

EDIT: this COULD BE a better approach if "wakefullness" wouldn't be part of the requirements. But it is. Since there is no guarantee that Service started by AlarmManager will get a chance to acquire a wake lock - this approach is not suitable for OP's case.

Please note that broadcasts and custom permissions were designed in order to introduce "decoupling" at application level - this scheme allows for sender application to be completely agnostic of the receiving application, as long as they agree on one custom permission (well, the same scheme is employed for pre-installed public permissions as well, but you wouldn't want to guard your sensitive data with a public permission).

In your case, however, sender and receiver are the same application. In such setting you don't really need all the trouble associated with broadcasts - just construct PendingIntent that starts the required Service inside your app, and you get it all at once:

  • PendingIntent and the associated Intent start a specific Service in your application (by name), therefore no other application can intercept it (theoretically, remember the above discussion).
  • Target Service can be non-exported, therefore no other application can access it in any way.

You welcome :)

Vasiliy
  • 16,221
  • 11
  • 71
  • 127
  • Well @Vasiliy just wow. Such an unexpected and detailed answer. I was aware of this system broad availability of broadcasts that is why I've asked the question. In my app where I have a service that needs to talk to a activity I've used `LocalBroadcastReceiver` given that it does not rise security issues. As for intents, instead of passing "private" data I switched to passing a database id and retrieve the row when the app is awaken. I've used `WakefulBroadcastReceiver` because it seemed a convenient way of keeping a wakelock. I need to handle the wake in my IntentService without it, right? – Alin Jan 31 '17 at 07:58
  • 1
    @Alin, I'm sorry - I was dragged away by security/privacy part of the question and missed the "wakefulness" requirement. Unfortunately, to my best knowledge, there is no guarantee that the `Service` started by `AlarmManager` will have a chance to acquire a wake lock before device goes to sleep. Therefore, if "wakefullness" is a requirement, you will have to use `BroadcastReceiver`. I will edit the answer in order not to mislead other people. – Vasiliy Jan 31 '17 at 09:20
  • Well if I make it like in my other question: http://stackoverflow.com/questions/41953458/aquire-partial-wakelock-in-a-intentservice I do think that the service will get a chance to aquire wake... because it is the first thing it does... And since I need the service to be called from either activity or alarm, I need a mechanism to hold wake in the service itself. Makes sense? – Alin Jan 31 '17 at 09:25
  • @Alin, I will answer in the other question. – Vasiliy Jan 31 '17 at 09:46
  • seems like I may be stuck with `WakefullBroadcastReceiver`... Having `exported=false' added to it, prevent it from being called by external sources? Would this add extra security? – Alin Jan 31 '17 at 10:40
  • @Alin, I didn't know that `BroadcastReceiver` can be non-exported... Thanks. This seems like a good fit in your case. – Vasiliy Jan 31 '17 at 12:25