ペンディング インテント

OWASP カテゴリ: MASVS-PLATFORM: プラットフォームのインタラクション

概要

PendingIntent は、システムによって管理されているトークンへの参照です。アプリ B がアプリ A に代わって事前定義されたアクションを実行できるようにするために、アプリ A が PendingIntent をアプリ B に渡すことができます。アプリ A がまだ動作しているかどうかは関係ありません。

リスク: 変更可能なペンディング インテント

PendingIntent は変更可能にすることができます。具体的には、アクションを指定する内部インテントは、fillIn() のドキュメントに記載されているロジックに従ってアプリ B が更新できます。つまり、PendingIntent の未入力フィールドを悪意のあるアプリが変更し、脆弱性が存在するアプリのエクスポートされていないコンポーネントにアクセスできるようになる可能性があります。

影響

この脆弱性の影響は、ターゲットになっているエクスポートされていないアプリの機能の実装によって異なります。

リスクの軽減

全般

最悪の脆弱性を回避するため、アクション、コンポーネント、パッケージが設定されていることを確認します。

Kotlin

val intent = Intent(intentAction)

// Or other component setting APIs e.g. setComponent, setClass
intent.setClassName(packageName, className)

PendingIntent pendingIntent =
    PendingIntent.getActivity(
        context,
        /* requestCode = */ 0,
        intent, /* flags = */ PendingIntent.FLAG_IMMUTABLE
    )

Java

Intent intent = new Intent(intentAction);

// Or other component setting APIs e.g. setComponent, setClass
intent.setClassName(packageName, className);

PendingIntent pendingIntent =
        PendingIntent.getActivity(
            getContext(),
            /* requestCode= */ 0,
            intent, /* flags= */ 0);

フラグ IMMUTABLE

アプリが Android 6(API レベル 23)以降をターゲットとする場合は、変更の可否を指定します。たとえば、FLAG_IMMUTABLE を使用して、悪意のあるアプリケーションによって未入力フィールドに入力されないようにできます。

Kotlin

val pendingIntent =
    PendingIntent.getActivity(
        context,
        /* requestCode = */ 0,
        Intent(intentAction),
        PendingIntent.FLAG_IMMUTABLE)

Java

PendingIntent pendingIntent =
        PendingIntent.getActivity(
            getContext(),
            /* requestCode= */ 0,
            new Intent(intentAction),
            PendingIntent.FLAG_IMMUTABLE);

Android 11(API レベル 30)以降では、どのフィールドが変更可能かを指定する必要があるため、この種の意図しない脆弱性は軽減されます。

参考資料


リスク: ペンディング インテントのリプレイ

PendingIntent は、FLAG_ONE_SHOT フラグが設定されていない限り、リプレイが可能です。リプレイ攻撃(繰り返してはならないアクションの実行)を防ぐには、FLAG_ONE_SHOT を使用することが重要です。

影響

この脆弱性の影響は、インテントを受け取る側の実装によって異なります。FLAG_ONE_SHOT フラグを設定せずに作成された PendingIntent を利用する悪意のあるアプリは、インテントをキャプチャして再利用し、一度しか実行できないアクションを繰り返す可能性があります。

リスクの軽減

複数回実行されることを意図していないペンディング インテントは、リプレイ攻撃を避けるために FLAG_ONE_SHOT フラグを使用する必要があります。

Kotlin

val pendingIntent =
      PendingIntent.getActivity(
          context,
          /* requestCode = */ 0,
          Intent(intentAction),
          PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_ONE_SHOT)

Java

PendingIntent pendingIntent =
        PendingIntent.getActivity(
            getContext(),
            /* requestCode= */ 0,
            new Intent(intentAction),
            PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT);

参考資料


参考資料