인텐트 리디렉션
컬렉션을 사용해 정리하기
내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요.
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)
}
자바
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()
로 전달하는 등 즉시 중첩된 인텐트를 사용하여 앱 구성요소를 시작합니다.
리소스
맞춤 콘텐츠
- 참고: JavaScript가 사용 중지되어 있으면 링크 텍스트가 표시됩니다.
- 대기 중인 인텐트
이 페이지에 나와 있는 콘텐츠와 코드 샘플에는 콘텐츠 라이선스에서 설명하는 라이선스가 적용됩니다. 자바 및 OpenJDK는 Oracle 및 Oracle 계열사의 상표 또는 등록 상표입니다.
최종 업데이트: 2023-12-15(UTC)
[[["이해하기 쉬움","easyToUnderstand","thumb-up"],["문제가 해결됨","solvedMyProblem","thumb-up"],["기타","otherUp","thumb-up"]],[["필요한 정보가 없음","missingTheInformationINeed","thumb-down"],["너무 복잡함/단계 수가 너무 많음","tooComplicatedTooManySteps","thumb-down"],["오래됨","outOfDate","thumb-down"],["번역 문제","translationIssue","thumb-down"],["샘플/코드 문제","samplesCodeIssue","thumb-down"],["기타","otherDown","thumb-down"]],["최종 업데이트: 2023-12-15(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)"]]