إعادة توجيه intent

فئة OWASP: MASVS-PLATFORM: Platform Interaction

نظرة عامة

تحدث عملية إعادة توجيه الغرض عندما يتمكّن أحد المهاجمين من التحكّم جزئيًا أو كليًا في محتوى الغرض المستخدَم لتشغيل مكوّن جديد في سياق تطبيق معرَّض للخطر.

يمكن توفير الغرض المستخدَم لتشغيل المكوّن الجديد بعدة طرق، أكثرها شيوعًا هو إما غرض متسلسل في حقل extras أو تحويله إلى سلسلة وتحليله. يمكن أن يؤدي التحكّم الجزئي في المَعلمات إلى النتيجة نفسها.

التأثير

وقد يختلف التأثير. قد ينفّذ المهاجم ميزات داخلية في التطبيق المعرَّض للخطر، أو قد يصل إلى مكوّنات خاصة مثل عناصر ContentProvider غير المُصدَّرة.

إجراءات التخفيف

بشكل عام، لا تعرض ميزات مرتبطة بإعادة توجيه النوايا المتداخلة. في الحالات التي لا يمكن تجنُّبها، اتّبِع طرق التخفيف التالية:

  • تنظيف المعلومات المجمّعة بشكل صحيح من المهم تذكُّر التحقّق من العلامات أو إزالتها (FLAG_GRANT_READ_URI_PERMISSION, FLAG_GRANT_WRITE_URI_PERMISSION, FLAG_GRANT_PERSISTABLE_URI_PERMISSION, and FLAG_GRANT_PREFIX_URI_PERMISSION)، والتحقّق من المكان الذي يتم إعادة توجيه الغرض إليه. يمكن أن يساعدك فريق IntentSanitizer في هذه العملية.
  • استخدِم عناصر PendingIntent. يمنع ذلك تصدير المكوّن ويجعل الغرض من إجراء الاستهداف غير قابل للتغيير.

يمكن أن تتحقّق التطبيقات من مكان إعادة توجيه Intent باستخدام طرق مثل 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);

حماية تلقائية

يقدّم نظام التشغيل Android 16 حلاً تلقائيًا لتعزيز الأمان بهدف Intent الحدّ من عمليات الاستغلال التي تتم من خلال إعادة التوجيه. في معظم الحالات، لن تواجه التطبيقات التي تستخدم الأهداف أي مشاكل في التوافق.

إيقاف معالجة إعادة التوجيه المستندة إلى النية

يقدّم Android 16 واجهة برمجة تطبيقات جديدة تتيح للتطبيقات إيقاف ميزات الحماية عند التشغيل. وقد يكون ذلك ضروريًا في حالات معيّنة يتداخل فيها السلوك الأمني التلقائي مع حالات الاستخدام المشروعة للتطبيق.

في Android 16، يمكنك إيقاف ميزات الحماية من خلال استخدام طريقة removeLaunchSecurityProtection() في عنصر Intent. على سبيل المثال:

val i = intent
val iSublevel: Intent? = i.getParcelableExtra("sub_intent")
iSublevel?.removeLaunchSecurityProtection() // Opt out from hardening
iSublevel?.let { startActivity(it) }

أخطاء شائعة

  • التحقّق مما إذا كانت getCallingActivity() تعرض قيمة غير فارغة يمكن للتطبيقات الضارة تقديم قيمة فارغة لهذه الدالة.
  • بافتراض أنّ checkCallingPermission() تعمل في جميع السياقات، أو أنّ الطريقة تعرض استثناءً عندما تُرجع عددًا صحيحًا.

ميزات تصحيح الأخطاء

بالنسبة إلى التطبيقات التي تستهدف الإصدار 12 من نظام التشغيل Android (المستوى 31 لواجهة برمجة التطبيقات) أو الإصدارات الأحدث، يمكنك تفعيل ميزة تصحيح الأخطاء التي تساعدك في بعض الحالات على رصد ما إذا كان تطبيقك ينفّذ عملية إطلاق غير آمنة لغرض.

إذا كان تطبيقك ينفّذ كلا الإجراءَين التاليَين، سيرصد النظام عملية تشغيل غير آمنة لغرض، وسيحدث انتهاك StrictMode:

  • يفكّ تطبيقك حزمة هدف متداخل من الإضافات الخاصة بهدف تم تسليمه.
  • يبدأ تطبيقك على الفور أحد مكونات التطبيق باستخدام هذا الغرض المتداخل، مثل تمرير الغرض إلى startActivity() أو startService() أو bindService().

الموارد