CodeQL 文档

使用隐式 PendingIntents

ID: java/android/implicit-pendingintents
Kind: path-problem
Security severity: 8.2
Severity: error
Precision: high
Tags:
   - security
   - external/cwe/cwe-927
Query suites:
   - java-code-scanning.qls
   - java-security-extended.qls
   - java-security-and-quality.qls

单击以在 CodeQL 存储库中查看查询

PendingIntent 用于包装将在另一个应用程序中提供和执行的 Intent。当 Intent 执行时,它的行为就好像是由提供应用程序直接运行的,使用该应用程序的权限。

如果 PendingIntent 配置为可变的,则接收应用程序可以更改其内部 Intent 的字段(前提是它们之前未设置)。这意味着,如果未定义目标组件(即隐式 PendingIntent)的可变 PendingIntent 可以被更改以使用创建它的应用程序的权限执行任意操作。

恶意应用程序可以访问隐式 PendingIntent,如下所示

  • 它被包装并作为另一个隐式 Intent 的额外信息发送。

  • 它被发送为 Slide 的操作。

  • 它被发送为 Notification 的操作。

获得访问权限后,攻击者可以修改底层的 Intent 并使用提升的权限执行任意操作。这可能会让恶意应用程序访问受害者应用程序的私有组件,或者能够在没有必要权限的情况下执行操作。

建议

避免创建隐式 PendingIntent。这意味着底层的 Intent 应该始终具有显式目标组件。

当您将 PendingIntent 作为另一个 Intent 的额外内容添加时,请确保此第二个 Intent 也具有显式目标组件,以防止它被传递到不受信任的应用程序。

尽可能使用标志 FLAG_IMMUTABLE 创建 PendingIntent,以防止目标组件修改底层 Intent 的空字段。

示例

在以下示例中,创建了一个 PendingIntent 并将其包装为另一个 Intent 的额外内容。

在第一个示例中,PendingIntent 和其包装的 Intent 都是隐式的,使它们容易受到攻击。

在第二个示例中,通过向 PendingIntent 和包装的 Intent 添加显式目标组件,避免了这个问题。

第三个示例使用 FLAG_IMMUTABLE 标志来防止底层 Intent 被目标组件修改。

import android.app.Activity;
import android.app.PendingIntent;
import android.content.Intent;
import android.os.Bundle;

public class ImplicitPendingIntents extends Activity {

	public void onCreate(Bundle savedInstance) {
		{
			// BAD: an implicit Intent is used to create a PendingIntent.
			// The PendingIntent is then added to another implicit Intent
			// and started.
			Intent baseIntent = new Intent();
			PendingIntent pi =
					PendingIntent.getActivity(this, 0, baseIntent, PendingIntent.FLAG_ONE_SHOT);
			Intent fwdIntent = new Intent("SOME_ACTION");
			fwdIntent.putExtra("fwdIntent", pi);
			sendBroadcast(fwdIntent);
		}

		{
			// GOOD: both the PendingIntent and the wrapping Intent are explicit.
			Intent safeIntent = new Intent(this, AnotherActivity.class);
			PendingIntent pi =
					PendingIntent.getActivity(this, 0, safeIntent, PendingIntent.FLAG_ONE_SHOT);
			Intent fwdIntent = new Intent();
			fwdIntent.setClassName("destination.package", "DestinationClass");
			fwdIntent.putExtra("fwdIntent", pi);
			startActivity(fwdIntent);
		}

		{
			// GOOD: The PendingIntent is created with FLAG_IMMUTABLE.
			Intent baseIntent = new Intent("SOME_ACTION");
			PendingIntent pi =
					PendingIntent.getActivity(this, 0, baseIntent, PendingIntent.FLAG_IMMUTABLE);
			Intent fwdIntent = new Intent();
			fwdIntent.setClassName("destination.package", "DestinationClass");
			fwdIntent.putExtra("fwdIntent", pi);
			startActivity(fwdIntent);
		}
	}
}

参考资料

  • ©GitHub, Inc.
  • 条款
  • 隐私