インテント リダイレクト
コレクションでコンテンツを整理
必要に応じて、コンテンツの保存と分類を行います。
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()
にインテントを渡して)、直ちにアプリ コンポーネントを開始した。
参考資料
あなたへのおすすめ
このページのコンテンツやコードサンプルは、コンテンツ ライセンスに記載のライセンスに従います。Java および OpenJDK は Oracle および関連会社の商標または登録商標です。
最終更新日 2024-02-23 UTC。
[null,null,["最終更新日 2024-02-23 UTC。"],[],[],null,["# Intent redirection\n\n\u003cbr /\u003e\n\n**OWASP category:** [MASVS-PLATFORM: Platform Interaction](https://mas.owasp.org/MASVS/09-MASVS-PLATFORM)\n\nOverview\n--------\n\nAn intent redirection occurs when an attacker can partly or fully control the\ncontents of an intent used to launch a new component in the context of a\nvulnerable app.\n\nThe intent used to launch the new component can be supplied in several ways,\nmost commonly either as a serialized intent in an `extras` field, or marshaled\nto a string and parsed. Partial control of parameters can also lead to the same\nresult.\n\nImpact\n------\n\nThe impact can vary. An attacker might execute internal features in the\nvulnerable app, or it might access private components like unexported\nContentProvider objects.\n\nMitigations\n-----------\n\nIn general, don't expose features related to redirecting nested intents. In\ncases where it's unavoidable, apply the following mitigation methods:\n\n- Properly sanitize the bundled information. It's important to remember to check or clear flags (`FLAG_GRANT_READ_URI_PERMISSION,\n FLAG_GRANT_WRITE_URI_PERMISSION, FLAG_GRANT_PERSISTABLE_URI_PERMISSION, and\n FLAG_GRANT_PREFIX_URI_PERMISSION`), and to check where the intent is being redirected. [`IntentSanitizer`](/reference/kotlin/androidx/core/content/IntentSanitizer) can help with this process.\n- Use [`PendingIntent`](/guide/components/intents-filters#PendingIntent) objects. This prevents your component from being exported and makes the target action intent immutable.\n\nApps can check where an intent is being redirected using methods such as\n[`ResolveActivity`](/reference/android/content/Intent#resolveActivity(android.content.pm.PackageManager)): \n\n### Kotlin\n\n val intent = getIntent()\n // Get the component name of the nested intent.\n val forward = intent.getParcelableExtra\u003cParcelable\u003e(\"key\") as Intent\n val name: ComponentName = forward.resolveActivity(packageManager)\n // Check that the package name and class name contain the expected values.\n if (name.packagename == \"safe_package\" && name.className == \"safe_class\") {\n // Redirect the nested intent.\n startActivity(forward)\n }\n\n### Java\n\n Intent intent = getIntent()\n // Get the component name of the nested intent.\n Intent forward = (Intent) intent.getParcelableExtra(\"key\");\n ComponentName name = forward.resolveActivity(getPackageManager());\n // Check that the package name and class name contain the expected values.\n if (name.getPackageName().equals(\"safe_package\") &&\n name.getClassName().equals(\"safe_class\")) {\n // Redirect the nested intent.\n startActivity(forward);\n }\n\nApps can use [`IntentSanitizer`](/reference/kotlin/androidx/core/content/IntentSanitizer) using logic similar to the\nfollowing: \n\n### Kotlin\n\n val intent = IntentSanitizer.Builder()\n .allowComponent(\"com.example.ActivityA\")\n .allowData(\"com.example\")\n .allowType(\"text/plain\")\n .build()\n .sanitizeByThrowing(intent)\n\n### Java\n\n Intent intent = new IntentSanitizer.Builder()\n .allowComponent(\"com.example.ActivityA\")\n .allowData(\"com.example\")\n .allowType(\"text/plain\")\n .build()\n .sanitizeByThrowing(intent);\n\n#### Default protection\n\nAndroid 16 introduces a by-default security hardening solution to `Intent`\nredirection exploits. In most cases, apps that use intents normally won't\nexperience any compatibility issues.\n\n##### Opt out of Intent redirection handling\n\nAndroid 16 introduces a new API that allows apps to opt out of launch security\nprotections. This might be necessary in specific cases where the default\nsecurity behavior interferes with legitimate app use cases.\n| **Important:** Opting out of security protections should be done with caution and only when absolutely necessary, as it can increase the risk of security vulnerabilities. Carefully assess the potential impact on your app's security before using this API.\n\nIn Android 16, you can opt out of security protections by using the\n`removeLaunchSecurityProtection()` method on the `Intent` object. For example: \n\n val i = intent\n val iSublevel: Intent? = i.getParcelableExtra(\"sub_intent\")\n iSublevel?.removeLaunchSecurityProtection() // Opt out from hardening\n iSublevel?.let { startActivity(it) }\n\n#### Common mistakes\n\n- Checking if `getCallingActivity()` returns a non-null value. Malicious apps can supply a null value for this function.\n- Assuming that `checkCallingPermission()` works in all contexts, or that the method throws an exception when it is actually returning an integer.\n\n#### Debugging features\n\nFor apps that target Android 12 (API level 31) or higher, you can enable a\n[debugging feature](/guide/components/intents-filters#DetectUnsafeIntentLaunches) that, in some cases, helps you detect whether your app is\nperforming an unsafe launch of an intent.\n\nIf your app performs **both** of the following actions, the system detects an\nunsafe intent launch, and a `StrictMode` violation occurs:\n\n- Your app unparcels a nested intent from the extras of a delivered intent.\n- Your app immediately starts an app component using that nested intent, such as passing the intent into `startActivity()`, `startService()`, or `bindService()`.\n\nResources\n---------\n\n- [Remediation for Intent Redirection](https://support.google.com/faqs/answer/9267555)\n- [Intents and intent filters](/guide/components/intents-filters#DetectUnsafeIntentLaunches)"]]