Secured Broadcasts and SMS Clients
Some broadcast Intent
s can only be broadcast by the system. Sometimes,
these will be documented as such. For example, only the system can
broadcast ACTION_DEVICE_STORAGE_LOW
, and
the JavaDocs for that Intent
action
state:
This is a protected intent that can only be sent by the system.
Hence, assuming that there are no bugs in the system, your apps can rest assured that if you receive such a broadcast, it was really sent by the system, and was not spoofed by some rogue app on the device.
However, there are some system Intent
actions that are secured somewhat
differently, where the broadcaster holds some permission. Your app can
require that permission (e.g., android:permission
on your <receiver>
in the manifest) to ensure that you will only receive broadcasts by somebody
holding that permission. Doing this, once again, can help prevent your
app from being spoofed by malware or other miscreant apps on a user’s
device.
For example, take SMS.
It is 2013, and Google steadfastly refuses to document the means by which an app can receive SMS messages. One downside to their stubbornness in this area is that app developers may not know how to protect their apps from being spoofed.
The undocumented SMS_RECEIVED
Intent
action is used for an ordered
broadcast that is sent when an SMS arrives. By default, only one app
will receive it: whatever the device’s default SMS client is. But, users
can install third-party apps that also receive this broadcast, and those
apps can use android:priority
to arrange to get the message before
the default client.
However, not only is that Intent
action undocumented, but so is the
means to prevent your app from being spoofed. After all, if SMS_RECEIVED
is just a broadcast Intent
, what’s to stop any other app from sending
that broadcast itself, fooling other apps on the device into thinking that
an SMS arrived?
The answer lies in a permission: android.permission.BROADCAST_SMS
. This
particular permission actually is documented,
albeit not especially well.
If you look at the AOSP messaging app’s manifest,
you will see that the <receiver>
for SMS_RECEIVED
requires this permission.
And, that permission is a signature
-level permission, meaning that apps
can only hold that permission if they are signed by the same signing key as
the app that defined the permission. In this case, the platform itself
defines the permission, and so to hold BROADCAST_SMS
, the app has to be
signed by the signing key of the device’s firmware, which usually means that
the app is part of that firmware, whether it is device firmware or a third-party
ROM mod.
SMS client apps that do not mirror what the AOSP client does – requiring
senders of SMS_RECEIVED
to hold BROADCAST_SMS
– are at risk of having
other apps send spoof SMSes to them. For example, malware could use this
to deliver fake SMS messages to the user,
containing links to yet more malware.
If you are implementing an SMS client, it behooves you to add
android:permission="android.permission.BROADCAST_SMS"
to your
<receiver>
that handles your SMS broadcasts.