CodeQL 文档

Android 片段注入

ID: java/android/fragment-injection
Kind: path-problem
Security severity: 9.8
Severity: error
Precision: high
Tags:
   - security
   - external/cwe/cwe-470
Query suites:
   - java-code-scanning.qls
   - java-security-extended.qls
   - java-security-and-quality.qls

单击以在 CodeQL 代码库中查看查询

当使用外部提供的名称实例化片段时,这会将任何动态创建和托管片段的导出活动暴露给片段注入。恶意应用程序可以提供任意片段的名称(甚至是未设计为可从外部访问的片段),并将其注入到活动中。这可以绕过访问控制,并使应用程序面临意外的影响。

片段是 Android 应用程序用户界面的可重用部分。尽管片段控制着自己的生命周期和布局,并处理自己的输入事件,但它不能独立存在:它必须由活动或其他片段托管。这意味着,通常情况下,只有当片段的托管活动本身被导出时,第三方应用程序才能访问该片段(即导出)。

建议

一般情况下,不要使用用户提供的名称实例化类(包括片段),除非该名称已经过适当验证。此外,如果导出的活动扩展了 PreferenceActivity 类,请确保重写了 isValidFragment 方法,并且仅当提供的 fragmentName 指向预期的片段时才返回 true

示例

以下示例展示了两种情况:第一种情况中,使用不受信任的数据实例化片段并将其添加到活动中,而第二种情况中,使用静态名称安全地添加了片段。

public class MyActivity extends FragmentActivity {

    @Override
    protected void onCreate(Bundle savedInstance) {
        try {
            super.onCreate(savedInstance);
            // BAD: Fragment instantiated from user input without validation
            {
                String fName = getIntent().getStringExtra("fragmentName");
                getFragmentManager().beginTransaction().replace(com.android.internal.R.id.prefs,
                        Fragment.instantiate(this, fName, null)).commit();
            }
            // GOOD: Fragment instantiated statically
            {
                getFragmentManager().beginTransaction()
                        .replace(com.android.internal.R.id.prefs, new MyFragment()).commit();
            }
        } catch (Exception e) {
        }
    }

}

下一个示例展示了两个扩展了 PreferenceActivity 的活动。第一个活动重写了 isValidFragment,但错误地无条件返回了 true。第二个活动正确地重写了 isValidFragment,以便仅当 fragmentName 是受信任的片段名称时才返回 true

class UnsafeActivity extends PreferenceActivity {

    @Override
    protected boolean isValidFragment(String fragmentName) {
        // BAD: any Fragment name can be provided.
        return true;
    }
}


class SafeActivity extends PreferenceActivity {
    @Override
    protected boolean isValidFragment(String fragmentName) {
        // Good: only trusted Fragment names are allowed.
        return SafeFragment1.class.getName().equals(fragmentName)
                || SafeFragment2.class.getName().equals(fragmentName)
                || SafeFragment3.class.getName().equals(fragmentName);
    }

}

参考

  • ©2025GitHub 公司
  • 条款
  • 隐私