Secured Broadcasts and SMS Clients

Some broadcast Intents 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.