インテント リダイレクト

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

概要

インテント リダイレクトは、脆弱なアプリに関連して新しいコンポーネントの起動に使用されるインテントの内容を、攻撃者が部分的または完全に制御できる場合に発生します。

新しいコンポーネントの起動に使用されるインテントは、いくつかの方法で指定できます。一般的な方法としては、extras フィールドでシリアル化されたインテントとして指定するか、文字列にマーシャリングして解析します。パラメータの部分的な制御でも同じ結果を得ることができます。

影響

影響はさまざまです。攻撃者は、脆弱なアプリの内部機能を実行することや、エクスポートされていない ContentProvider オブジェクトのような非公開コンポーネントにアクセスすることができます。

リスクの軽減

全般

一般的に、ネストされたインテントのリダイレクトに関連する機能は公開しないでください。公開する必要がある場合は、以下の軽減策を適用します。

  • バンドルされた情報を適切にサニタイズします。必ずフラグ(GRANT_URI_PERMISSIONS)のチェックまたはクリアを行い、インテントのリダイレクト先を確認することが重要です。このプロセスには IntentSanitizer が役立ちます。
  • PendingIntent オブジェクトを使用します。これにより、コンポーネントがエクスポートされなくなり、ターゲット アクション インテントが不変になります。

アプリでは、ResolveActivity などのメソッドを使用して、インテントのリダイレクト先を確認できます。

Kotlin

val intent = getIntent()
// Get the component name of the nested intent.
val forward = intent.getParcelableExtra<Parcelable>("key") as Intent
val name: ComponentName = forward.resolveActivity(packageManager)
// Check that the package name and class name contain the expected values.
if (name.packagename == "safe_package" && name.className == "safe_class") {
    // Redirect the nested intent.
    startActivity(forward)
}

Java

Intent intent = getIntent()
// Get the component name of the nested intent.
Intent forward = (Intent) intent.getParcelableExtra("key");
ComponentName name = forward.resolveActivity(getPackageManager());
// Check that the package name and class name contain the expected values.
if (name.getPackageName().equals("safe_package") &&
        name.getClassName().equals("safe_class")) {
    // Redirect the nested intent.
    startActivity(forward);
}

アプリで IntentSanitizer を使用するには、次のようなロジックを使用します。

Kotlin

val intent = IntentSanitizer.Builder()
     .allowComponent("com.example.ActivityA")
     .allowData("com.example")
     .allowType("text/plain")
     .build()
     .sanitizeByThrowing(intent)

Java

Intent intent = new  IntentSanitizer.Builder()
     .allowComponent("com.example.ActivityA")
     .allowData("com.example")
     .allowType("text/plain")
     .build()
     .sanitizeByThrowing(intent);

よくあるミス

  • getCallingActivity() が null 以外の値を返すかどうかをチェックする。悪意のあるアプリがこの関数に null 値を渡すことがあります。
  • checkCallingPermission() がすべてのコンテキストで機能すると仮定する。または、メソッドが実際に整数を返すときに例外をスローすると仮定する。

デバッグ機能

Android 12(API レベル 31)以降をターゲットとするアプリでは、デバッグ機能を有効にできます。これにより、いくつかのケースでアプリがインテントの安全でない起動を実行しているかどうかを検出できます。

アプリが以下のアクションの両方を実行した場合、システムによってインテントの安全でない起動が検出され、StrictMode 違反が発生します。

  • 配信されたインテントのエクストラから、ネストされたインテントを取り出した。
  • そのネストされたインテントを使用して(たとえば startActivity()startService()、または bindService() にインテントを渡して)、直ちにアプリ コンポーネントを開始した。

参考資料