blob: 1fff3d5158aa58a6a2278a17f5e85d237996e8b1 [file] [log] [blame] [view]
Robert Sesek250f67c2019-06-13 00:21:121# Android IPC Security Considerations
2
3Generally Chrome communicates between its processes using the
4[Mojo](../../mojo/README.md) [inter-process communication (IPC)
5mechanism](mojo.md). For most features, this is the preferred IPC mechanism to
6use. However, as an Android application, there are certain interactions with
7other applications and the Android OS that necessitate using different IPC
8mechanisms to communicate. This document covers security concerns related to
9those Android-specific IPC mechanisms.
10
11The Chrome browser process is typically the only process type that will interact
12with these different IPC mechanisms.
13
14## Intents
15
16[Intents](https://developer.android.com/guide/components/intents-filters) are
17the most common type of inter-process communication mechanism on Android. They
18are most commonly used to start Activities and they internally carry data
19associated with that Activity (e.g. using the `ACTION_SEND` Intent to share a
20piece of content and including either text or image data in the Intent body).
21
22### Inbound Intents
23
24Because any application can dispatch Intents with Chrome as the receiver, when
25receiving an inbound Intent, you should never fully trust the data contained
26within. Data sent from other applications could be malicious or malformed, and
27so you must validate or sanitze the data before passing it to other trusted
28components of the browser process. Intents are handled in Java though, so
29following the [Rule of 2](rule-of-2.md) is generally easy. (Though take note
30that certain Android classes are just Java wrappers around native code, which
31would not be considered safe by that rule.)
32
Robert Sesek53253332022-10-28 20:06:1633Inbound Intents may also pose deserialization issues via the data stored in an
34Intent's extras. These issues may result in non-exploitable crashes (e.g.
35https://crbug.com/1232099), but it is also possible to have deserialization
36vulnerabilities with security implications. Always use the
37[`IntentUtils.safe*Extra()`](https://source.chromium.org/chromium/chromium/src/+/main:base/android/java/src/org/chromium/base/IntentUtils.java;l=58;drc=7f1297bacd32fe668d4c99cb8963b56aed363acc)
38family of methods to access Intent extra fields from inbound Intents.
39
Robert Sesek277dd722021-05-24 21:24:0740It is **fundamentally impossible** to determine the sender of an Intent, unless
41the Activity was started with
42[`startActivityForResult`](https://developer.android.com/reference/android/app/Activity#startActivityForResult(android.content.Intent,%20int)).
43For Intents that are started via `startActivityForResult`, you can use
44[`getCallingActivity`](https://developer.android.com/reference/android/app/Activity#getCallingActivity())
45or
46[`getCallingPackage`](https://developer.android.com/reference/android/app/Activity#getCallingPackage())
47to retrieve the identity of the component that called
48[`setResult`](https://developer.android.com/reference/android/app/Activity#setResult(int))
49on the started Activity. For all other cases, the security model of your feature
50cannot depend on authenticating the sender of an Intent. Do not trust
51`Intent.EXTRA_REFERRER`. See also the discussion below about [capability
52tokens](#capability-tokens).
Robert Sesek250f67c2019-06-13 00:21:1253
54One way to authorize Intents is to use the system's
55[`android:permission`](https://developer.android.com/guide/topics/permissions/overview#permission_enforcement)
56attribute on a component's (e.g. Activity, Service, etc.) manifest declaration.
57You can [define a custom permission](https://developer.android.com/guide/topics/permissions/defining) and
58set the `android:protectionLevel` of the permission to `"signature"` or
59`"signatureOrSystem"` to restrict access to just components signed by the same
60certificate (or trusted system components).
61
62## Outbound Intents {#outbound-intents}
63
64There are [two types of Intents](https://developer.android.com/guide/components/intents-filters?hl=en#Types):
65implicit and explicit. With implicit Intents, the receiving application is not
66specified by the sender and the system uses a resolution process to find the
67most suitable component to handle it. An implicit Intent can sometimes result in
68a chooser being shown to the user when multiple applications could handle it.
69Explicit Intents specify either the package name or a fully qualified
70`ComponentName`, so the recipient is known at the time it is dispatched.
71Implicit Intents can result in an unexpected (and maybe malicious) application
72receiving user data. If it is possible to know the target application when
73sending an Intent, always prefer using an explicit Intent.
74
75## PendingIntents
76
77A [PendingIntent](https://developer.android.com/reference/android/app/PendingIntent)
78is created by one application and vended to another. The object allows the
79receiving application to start the component (i.e. Activity, Service, Broadcast)
80_as if the creating application started it_. Similar to a [setuid binary](https://en.wikipedia.org/wiki/Setuid),
81you must use this with care, as it can even be used to start non-exported
82components of the creating application.
83
84It is possible to retrieve information about the creator package of the
85PendingIntent using the [`getCreatorPackage()`](https://developer.android.com/reference/android/app/PendingIntent.html#getCreatorPackage())
86method. This is the identity under which the Intent, which the PendingIntent
87represents, will be started. Note that you cannot retrieve specific information
88about the Intent (e.g. its target and extras). And as discussed above with
89Intents, it is not possible to determine the application that called
90`PendingIntent.send()`.
91
92## Binder
93
94[Binder](https://developer.android.com/reference/android/os/Binder) is the low
95level IPC mechanism on Android, and it is what Intents and other Framework-level
96primitives are built upon.
97
98### Bound Services
99
100To communicate between components using Binder, you declare a `<service>` in
101your manifest and connect to it using [`Context.bindService()`](https://developer.android.com/reference/android/content/Context.html#bindService(android.content.Intent,%2520android.content.ServiceConnection,%2520int)).
102This is referred to a as a [bound service](https://developer.android.com/guide/components/bound-services).
103
104One of the powerful properties of a bound service is that you can determine the
105identity of your communicating peer. This can only be done during a Binder
106transaction (e.g. in an [AIDL](https://developer.android.com/guide/components/aidl)
107method implementation or a [`Handler.Callback`](https://developer.android.com/reference/android/os/Handler.Callback.html))
108that is **not** marked [`FLAG_ONEWAY`](https://developer.android.com/reference/android/os/IBinder).
109During the transaction use [`Binder.getCallingUid()`](https://developer.android.com/reference/android/os/Binder.html#getCallingUid())
110to retrieve the package's UID.
111
112In Android, every installed application is given a unique user ID (UID). This
113can be used as a key to query the [PackageManager](https://developer.android.com/reference/android/content/pm/PackageManager),
114to retrieve the [PackageInfo](https://developer.android.com/reference/android/content/pm/PackageInfo)
115for the application. With the PackageInfo, information about the applications
116code signing certificates can be retrieved and cryptographically authenticated.
117This is a strong authentication check and it is the **only** reliable mechanism
118by which you can authenticate your peer.
119
120In Chrome, the helper functions
121[`ExternalAuthUtils.isCallerValid()`](https://cs.chromium.org/chromium/src/chrome/android/java/src/org/chromium/chrome/browser/externalauth/ExternalAuthUtils.java?l=157&rcl=fa790f69ce80bf2e192d710ea08b8343cad93fbb)
122and `isCallerValidForPackage()` can perform these checks for you.
123
124## Capability Tokens {#capability-tokens}
125
126We define a **capability token** to be an unforgeable object that the holder may
127present to another application as authentication to access a specific
128capability. Binder objects are backed by the kernel (i.e. are unforgeable), are
129transferable, and are comparable using `isEqual()`, so Binders can be used as
130capability tokens.
131
132One security factor to bear in mind is that because capability tokens are
133transferable, they do not strongly authenticate a caller's identity. One
134application may deliberately or accidentally transfer a capability token to
135another application, or a token could be exfiltrated via an application logic
136vulnerability. Therefore, only use capability tokens for access control, not
137identity authentication.
138
139While noting the above factor, capability tokens can be useful for
140authenticating Intents. If two applications have established a Binder
141connection, they can use the channel to exchange a capability token. One
142application constructs a generic Binder (using the
143[`Binder(String)`](https://developer.android.com/reference/android/os/Binder.html#Binder(java.lang.String))
144constructor) and sends the object over that `ServiceConnection` to the other
145application, while retaining a reference to it.
146
147The generic Binder object can then be transmitted as an Intent extra when
148sending Intents between the two applications. By comparing the object with
149`Binder.isEqual()`, you can validate the capability token. Be sure to use an
150[explicit Intent](#outbound-intents) when sending such an Intent.
151
152This same approach can also be done with using a PendingIntent to a non-exported
153component as a capability token. Internally PendingIntents use a Binder token
154approach, so the only significant difference is the additional capability
155conferred by the PendingIntent to start a component.