Transmission of sensitive information in BroadcastReceiver
CRITICAL | |||
Detection method | DAST SENSITIVE INFO |
Description
An application puts sensitive information into an Intent
to launch BroadcastReceiver
. This can lead to interception of information by external applications.
Interprocess communication (IPC) on Android is conducted using a special object—Intent
. Parameters of Intent handlers are set in the main file of the application manifest—AndroidManifest.xml
, or, in case of dynamic BroadcastReceivers
, in the application's code. If an implicit Intent is used (the recipient is not specified explicitly or the broadcasting mechanism Broadcast
is used), the data in such message could be compromised. Moreover, malicious applications could use mechanisms of delegation of process control, such as implicit calls to application components or objects like PendingIntent, for interception of control and fishing attacks.
The following object types are dangerous: Activity
, Service
, BroadcastReceiver
and ContentProvider
, because they are open to communication with other applications and don't belong to system Android calls (such as android.intent.action.MAIN
). BroadcastReceiver
is, by default, open to interaction with other applications, so the interception of control or of an Intent
with confidential information is possible.
Recommendations
By sending a Broadcast containing sensitive information into an internal BroadcastReceiver
, explicit Intent
, Private BroadcastReceiver
or LocalBroadcastManager
should be used. Note, that an application must not include sensitive information into a public Broadcast.
To receive a Broadcast
you need to create BroadcastReceiver
. Risks from using BroadcastReceiver
and corresponding countermeasures vary depending on the type of a Broadcast
.
To find out what type of BroadcastReceiver
you are supposed to create, follow through the table and chart below. An application that receives a Broadcast is not able to check the name of the package from which the Broadcast has been sent, so it is not possible to create a partner BroadcastReceiver, (should be corrected) as is the case with Activity.
Type of BroadcastReceiver |
Description |
Private BroadcastReceiver |
BroadcastReceiver that can receive a Broadcast only from the same application, and is therefore the safest type |
Public BroadcastReceiver |
BroadcastReceiver that can receive a Broadcast from any application |
In-house BroadcastReceiver |
BroadcastReceiver that can receive a Broadcast only from other applications of the same developer |
In addition, BroadcastReceiver can be static or dynamic depending on the definition method.
|
Definition method |
Characteristics |
Static BroadcastReceiver |
By adding <receiver> elements into AndroidManifest.xml |
|
Dynamic BroadcastReceiver |
By calling a registerReceiver() method |
|
Example: creation of Private BroadcastReceiver
Private BroadcastReceiver is the safest type, because it can receive a Broadcast from the same application only. Private BroadcastReceiver can be defined as Static only.
Rules (receiving a Broadcast):
1. Explicitly set the "exported" attribute to "false"
2. Verify the received Intent and handle it in a secure manner despite the fact that it was sent from within the same application
3. You can put confidential information into the resulting Intent because it is sent and received within the same application
Definition of the component in AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.mobix.android.broadcast.privatereceiver" >
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:allowBackup="false" >
<!-- Private Broadcast Receiver -->
<!-- *** 1 *** Explicitly set the "exported" attribute to "false" -->
<receiver
android:name=".PrivateReceiver"
android:exported="false" />
<activity
android:name=".PrivateSenderActivity"
android:label="@string/app_name"
android:exported="true" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Receiving a Broadcast
package com.mobix.android.broadcast.privatereceiver;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
public class PrivateReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// *** 2 *** Verify the received Intent and handle it in a secure manner despite the fact that it was sent from within the same application
String param = intent.getStringExtra("PARAM");
Toast.makeText(context,
String.format("Received param: \"%s\"", param),
Toast.LENGTH_SHORT).show();
// *** 3 *** You can put confidential information into the resulting Intent because it is sent and received within the same application
setResultCode(Activity.RESULT_OK);
setResultData("Sensitive information");
abortBroadcast();
}
}
Rules (sending a Broadcast):
1. Use an explicit Intent indicating the name of BroadcastReceiver class within the application
2. You can send sensitive information
3. Verify the received result data and handle it in a secure manner despite the fact that it was sent from the BroadcastReceiver of the same application
package com.mobix.android.broadcast.privatereceiver;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
public class PrivateSenderActivity extends Activity {
public void onSendNormalClick(View view) {
// *** 1 *** Use an explicit Intent indicating the name of BroadcastReceiver class within the application
Intent intent = new Intent(this, PrivateReceiver.class);
// *** 2 *** You can send sensitive information
intent.putExtra("PARAM", "Sensitive information from sender");
sendBroadcast(intent);
}
public void onSendOrderedClick(View view) {
// *** 1 *** Use an explicit Intent indicating the name of BroadcastReceiver class within the application
Intent intent = new Intent(this, PrivateReceiver.class);
// *** 2 *** You can send sensitive information
intent.putExtra("PARAM", "Sensitive information from sender");
sendOrderedBroadcast(intent, null, mResultReceiver, null, 0, null, null);
}
private BroadcastReceiver mResultReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// *** 3 *** Verify the received result data and handle it in a secure manner despite the fact that it was sent from the BroadcastReceiver of the same application
// See section "Secure Handling of the Input Data"
String data = getResultData();
PrivateSenderActivity.this.logLine(
String.format("Received result: \"%s\"", data));
}
};
private TextView mLogView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mLogView = (TextView)findViewById(R.id.logview);
}
private void logLine(String line) {
mLogView.append(line);
mLogView.append("\n");
}
}
Links
- https://developer.android.com/guide/components/intents-filters.html
- https://developer.android.com/training/basics/intents/index.html
- https://cwe.mitre.org/data/definitions/927.html
- https://github.com/OWASP/owasp-mstg/blob/master/Document/0x05h-Testing-Platform-Interaction.md#testing-for-injection-flaws-mstg-platform-2