امنیت فعالیت

اندروید از کاربران در برابر برنامه‌های مخرب محافظت می‌کند و یک تجربه کاربری قابل اعتماد را ارائه می‌دهد. چارچوب Activity Security شامل قوانین و محدودیت‌های پلتفرم است. این قوانین و محدودیت‌ها از وقفه‌های ناخواسته رابط کاربری، ربودن وظایف و سایر تهدیدات امنیتی جلوگیری می‌کنند. این تهدیدات مربوط به زمان و نحوه نمایش اجزای برنامه روی صفحه است. یکی از اجزای کلیدی این چارچوب، شروع فعالیت‌ها از پس‌زمینه را محدود می‌کند.

محدودیت‌های راه‌اندازی فعالیت پس‌زمینه

راه‌اندازی فعالیت پس‌زمینه (BAL) زمانی رخ می‌دهد که برنامه‌ای که در پیش‌زمینه نیست، هیچ فعالیت قابل مشاهده‌ای ندارد، یا یک PendingIntent از برنامه دیگری دریافت می‌کند، سعی می‌کند یک فعالیت جدید را شروع کند. این یک راه‌اندازی فعالیت پس‌زمینه (BAL) است. در حالی که موارد استفاده مشروع وجود دارد، مانند زمانی که یک برنامه ساعت زنگ‌دار شروع می‌شود، BAL های نامحدود منجر به تجربه کاربری ضعیف و ایجاد آسیب‌پذیری‌های امنیتی می‌شوند.

چرا آنها محدود شده‌اند؟

از اندروید ۱۰ (سطح API ۲۹)، این پلتفرم محدودیت‌هایی را در مورد زمان شروع فعالیت برنامه‌ها در پس‌زمینه اعمال کرده است. این محافظت‌ها به جلوگیری از رفتار مخرب برنامه‌ها کمک می‌کنند و با کاهش سوءاستفاده‌های رایج، تجربه کاربر را بهبود می‌بخشند، از جمله:

  • ربودن رابط کاربری و تبلیغات پاپ‌آپ : یک برنامه در پس‌زمینه به‌طور غیرمنتظره‌ای یک فعالیت (اغلب یک تبلیغ) را در بالای برنامه‌ای که کاربر در حال حاضر با آن در تعامل است، اجرا می‌کند و جلسه (session) او را می‌رباید.
  • فیشینگ و جعل هویت : یک برنامه در پس‌زمینه، فعالیتی را اجرا می‌کند که هویت برنامه دیگری را جعل می‌کند (برای مثال، یک صفحه ورود جعلی برای یک برنامه قانونی) تا اعتبارنامه‌های کاربر را بدزدد. این کار اغلب از طریق حمله "Activity Sandwich" انجام می‌شود، که در آن یک فعالیت مخرب در پشته وظایف یک برنامه قانونی قرار می‌گیرد.
  • Tapjacking : یک برنامه در پس‌زمینه، فعالیتی شفاف یا مبهم را روی برنامه دیگری نمایش می‌دهد تا لمس‌های کاربر را شنود کرده و او را به انجام اقدامات ناخواسته ترغیب کند.
  • بیدارسازی برنامه : یک جزء پس‌زمینه از یک برنامه، اجزای پیش‌زمینه برنامه دیگر را بیدار می‌کند تا به‌طور غیرقانونی شاخص‌های کاربر فعال روزانه را افزایش دهد.

سرویس‌های پیش‌زمینه (برای وظایف جاری)

اگر برنامه شما نیاز به انجام یک کار طولانی مدت در پس زمینه دارد که کاربر باید از آن آگاه باشد، مانند پخش موسیقی یا پیگیری یک تمرین، باید از یک سرویس پیش‌زمینه استفاده کنید. یک سرویس پیش‌زمینه باید یک اعلان مداوم را نمایش دهد که کاربر نتواند آن را رد کند. این اعلان می‌تواند کنترل‌های تعاملی (به عنوان مثال، دکمه‌های پخش/مکث برای یک برنامه موسیقی) را ارائه دهد. این کار کاربر را مطلع و کنترل می‌کند، اما او را با یک فعالیت تمام صفحه متوقف نمی‌کند.

با دنبال کردن این سلسله مراتب - شروع با اعلان‌های استاندارد و تنها در صورت لزوم به گزینه‌های مزاحم‌تر - شما یک تجربه بهتر و قابل پیش‌بینی‌تر برای کاربران خود ایجاد می‌کنید.

چه زمانی شروع فعالیت‌های پس‌زمینه مجاز است (استثنائات)

یک برنامه می‌تواند در صورت برآورده شدن یکی از شرایط زیر، یک فعالیت را از پس‌زمینه شروع کند:

  • این برنامه یک پنجره قابل مشاهده دارد، مانند یک فعالیت در پیش‌زمینه.
  • این برنامه، ویرایشگر روش ورودی (IME) فعلی است.
  • این فعالیت از یک PendingIntent که توسط سیستم ارسال شده است (به عنوان مثال، از یک ضربه اعلان) آغاز می‌شود.
  • این برنامه مجوز SYSTEM_ALERT_WINDOW را که توسط کاربر اعطا شده است، دارد.
  • به این برنامه مجوز START_ACTIVITIES_FROM_BACKGROUND اعطا شده است.
  • این برنامه توسط سرویسی محدود شده است که مجوز شروع فعالیت‌های پس‌زمینه را دریافت کرده است.
  • راه‌اندازی توسط برنامه‌ی لانچر دستگاه آغاز می‌شود، مانند زمانی که کاربر روی آیکون برنامه ضربه می‌زند یا با یک ویجت تعامل می‌کند.
  • این راه‌اندازی از یک بخش اصلی سیستم عامل است که باید همیشه اجرا شود، مانند سرویس تلفنی که صفحه تماس ورودی را شروع می‌کند.

مقاوم‌سازی جدید و گزینه‌های انتخابی مورد نیاز

برای افزایش بیشتر امنیت، اندروید قوانین سختگیرانه‌تری را معرفی کرده است که مستلزم انتخاب صریح برنامه‌هایی است که PendingIntent و IntentSender برای راه‌اندازی فعالیت‌ها استفاده می‌کنند. راه‌اندازی فقط در صورتی مجاز است که برنامه‌ای که PendingIntent ایجاد کرده یا برنامه‌ای که آن را ارسال می‌کند، برای اعطای امتیازات راه‌اندازی پس‌زمینه به آن، موافقت کند.

در بیشتر موارد، برنامه‌ای که PendingIntent ارسال می‌کند باید برنامه‌ای باشد که باید انتخاب شود، زیرا معمولاً برنامه‌ای است که کاربر مستقیماً با آن در تعامل است (مثلاً با ضربه زدن روی یک دکمه).

فرستندگان باید برای PendingIntent انتخاب کنند

وقتی برنامه شما اندروید ۱۴ (سطح API ۳۴) یا بالاتر را هدف قرار می‌دهد، دیگر هنگام ارسال یک PendingIntent ، به طور پیش‌فرض امتیازات BAL خود را اعطا نمی‌کند. اگر صریحاً این گزینه را انتخاب نکنید، ممکن است راه‌اندازی فعالیت مسدود شود ، مگر اینکه سازنده PendingIntent قبلاً امتیازات خود را اعطا کرده باشد.

برای اطمینان از موفقیت‌آمیز بودن راه‌اندازی، فرستنده باید با فراخوانی ActivityOptions.setPendingIntentBackgroundActivityStartMode() اجازه اعطای امتیازات را بدهد و حالت پیشنهادی ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_IF_VISIBLE است (که در SDK 36 اضافه شده است).

این حالت، سختگیرانه‌تر و ایمن‌تر است. این حالت فقط در صورتی مجوز می‌دهد که برنامه‌ی فرستنده در لحظه‌ی ارسال PendingIntent روی صفحه نمایش قابل مشاهده باشد. این حالت، تضمین می‌کند که اجرای اکتیویتی نتیجه‌ی مستقیم تعامل کاربر با برنامه‌ی شما باشد.

جدول اهداف در انتظار
شکل ۱: جریان تصمیم‌گیری برای راه‌اندازی فعالیت‌های پس‌زمینه.

برای اعطای دسترسی‌ها از ActivityOptions.setPendingIntentBackgroundActivityStartMode() استفاده کنید.

// Sender Side
ActivityOptions options = ActivityOptions.makeBasic()
    .setPendingIntentBackgroundActivityStartMode(
        ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_IF_VISIBLE);

try {
    myPendingIntent.send(options.toBundle());
} catch (PendingIntent.CanceledException e) {
    Log.e(TAG, "The PendingIntent was canceled", e);
}
// Sender Side
val options = ActivityOptions.makeBasic().apply {
    pendingIntentBackgroundActivityStartMode = ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_IF_VISIBLE
}

try {
    myPendingIntent.send(options.toBundle())
} catch (e: PendingIntent.CanceledException) {
    Log.e(TAG, "The PendingIntent was canceled", e)
}

سازندگان باید برای PendingIntent انتخاب کنند

وقتی برنامه شما اندروید ۱۵ (سطح API 35) یا بالاتر را هدف قرار می‌دهد، برنامه‌ای که یک PendingIntent ایجاد می‌کند ، دیگر به طور پیش‌فرض امتیازات اجرای پس‌زمینه را به آن اعطا نمی‌کند. برای اینکه به فرستنده اجازه دهید از امتیازات BAL برنامه شما استفاده کند، باید صریحاً این گزینه را انتخاب کنید.

برای اعطای دسترسی‌ها از ActivityOptions.setPendingIntentCreatorBackgroundActivityStartMode() استفاده کنید.

// Creator Side
Intent intent = new Intent(context, MyActivity.class);
ActivityOptions options = ActivityOptions.makeBasic().setPendingIntentCreatorBackgroundActivityStartMode(ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);

PendingIntent pendingIntent = PendingIntent.getActivity(context, REQUEST_CODE, intent, PendingIntent.FLAG_IMMUTABLE, options.toBundle());
// Creator Side
val intent = Intent(context, MyActivity::class.java)
val options = ActivityOptions.makeBasic().apply {
    pendingIntentCreatorBackgroundActivityStartMode = ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
}

val pendingIntent = PendingIntent.getActivity(context, REQUEST_CODE, intent,
        PendingIntent.FLAG_IMMUTABLE, options.toBundle())

راه‌اندازی با IntentSender

همین محدودیت‌های BAL هنگام راه‌اندازی فعالیت‌ها با استفاده از IntentSender نیز اعمال می‌شوند. از آنجایی که IntentSender از طریق PendingIntent.getIntentSender به دست می‌آید، مشمول الزامات انتخاب مشابه است.

  • از اندروید ۱۴ (API 34) به بعد، استفاده از Context.startIntentSender() نیاز به یک گزینه‌ی انتخاب سمت فرستنده دارد. شما باید بسته‌ی ActivityOptions را نیز در اینجا ارائه دهید.
ActivityOptions options = ActivityOptions.makeBasic()
        .setPendingIntentBackgroundActivityStartMode(
            ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);

context.startIntentSender(myIntentSender, fillInIntent, flagsMask,
        flagsValues, extraFlags, options.toBundle());
val options = ActivityOptions.makeBasic().apply {
    pendingIntentBackgroundActivityStartMode = ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
}

context.startIntentSender(myIntentSender, fillInIntent, flagsMask,
        flagsValues, extraFlags, options.toBundle())
  • با شروع از اندروید ۱۷ (API 37+) استفاده از IntentSender.sendIntent() نیاز به یک گزینه انتخاب از طرف فرستنده دارد.
ActivityOptions options = ActivityOptions.makeBasic()
        .setPendingIntentBackgroundActivityStartMode(
            ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);

myIntentSender.sendIntent(context, code, intent, onFinished, handler,
        requiredPermission, options.toBundle());
val options = ActivityOptions.makeBasic().apply {
    pendingIntentBackgroundActivityStartMode = ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
}

myIntentSender.sendIntent(context, code, intent, onFinished, handler,
        requiredPermission, options.toBundle())

نمودار توالی: محدودیت‌های BAL

جدول اهداف در انتظار
شکل ۲: فرآیند راه‌اندازی ایمن یک اکتیویتی با استفاده از PendingIntent

این نمودار فرآیند راه‌اندازی ایمن یک فعالیت با استفاده از PendingIntent را نشان می‌دهد. راه‌اندازی موفقیت‌آمیز به یک زنجیره امتیاز معتبر بستگی دارد که در آن حداقل یکی از برنامه‌های شرکت‌کننده، هم امتیازات خود را اعطا می‌کند و هم توانایی راه‌اندازی یک فعالیت از پس‌زمینه را دارد.

  1. ایجاد و تفویض اختیار (برنامه الف - خالق)
    1. برنامه Creator، PendingIntent را می‌سازد.
    2. اگر هدف SDK 35+ باشد، سازنده باید صریحاً امتیازات BAL خود را با استفاده از setPendingIntentCreatorBackgroundActivityStartMode() تفویض کند تا از امتیازاتش استفاده شود. به طور پیش‌فرض، هیچ امتیازی تفویض نمی‌شود.
    3. سپس PendingIntent به برنامه دیگری (برنامه B) تحویل داده می‌شود.
  2. راه‌اندازی و مشارکت (اپلیکیشن ب - فرستنده)
    1. بعداً، برنامه‌ی فرستنده با فراخوانی PendingIntent.send() فرآیند راه‌اندازی را آغاز می‌کند.
    2. اگر هدف SDK 34+ باشد، فرستنده باید صریحاً امتیازات خود را با استفاده از setPendingIntentBackgroundActivityStartMode() ارائه دهد تا از امتیازاتش استفاده شود. به طور پیش‌فرض، هیچ امتیازی تفویض نمی‌شود.
  3. اعتبارسنجی امنیتی سیستم اندروید
    1. سیستم اندروید درخواست راه‌اندازی را رهگیری کرده و بررسی امنیتی انجام می‌دهد.
    2. دو شرط را ارزیابی می‌کند:
    3. آیا خالق، امتیازات خود را تفویض کرده است، و آیا برنامه خالق در حال حاضر یکی از استثنائات عمومی BAL را برآورده می‌کند؟
    4. آیا فرستنده امتیازات خود را ارائه داده است، و آیا برنامه فرستنده در حال حاضر یکی از استثنائات عمومی BAL را برآورده می‌کند؟
  4. نتیجه
    1. مجاز : اگر حداقل یکی از دو شرط مرحله ۳ برقرار باشد، زنجیره امتیاز اعتبارسنجی می‌شود. سیستم اندروید، اکتیویتی هدف را آغاز می‌کند و فرستنده نتیجه موفقیت‌آمیز بودن را دریافت می‌کند.
    2. مسدود شده : اگر هیچ یک از شرایط برقرار نباشد، سیستم اجرای برنامه را مسدود می‌کند. برنامه فرستنده هیچ مقدار بازگشتی مستقیم یا استثنایی که نشان‌دهنده‌ی شکست باشد دریافت نمی‌کند. در عوض، سیستم اندروید به صورت داخلی پیام « اجرای فعالیت پس‌زمینه مسدود شد! » را در Logcat ثبت می‌کند که توسعه‌دهندگان باید آن را برای اشکال‌زدایی بررسی کنند.

پیشگیری از ربودن وظیفه

برای جلوگیری از حملات ربودن اطلاعات در حین انجام وظیفه (مانند «Activity Sandwich»)، اندروید ۱۵ قوانین جدیدی را برای برنامه‌هایی که سطح API ۳۷ یا بالاتر را هدف قرار می‌دهند، معرفی می‌کند.

  • قانون ۱ : در یک وظیفه واحد، یک فعالیت فقط می‌تواند توسط فعالیت دیگری که متعلق به همان برنامه است (یعنی دارای همان شناسه کاربری) با بالاترین فعالیت فعلی در آن وظیفه است، راه‌اندازی شود.
  • قانون ۲ : فقط فعالیتی در یک وظیفه پیش‌زمینه که با شناسه کاربری (UID) بالاترین فعالیت مطابقت دارد، مجاز به ایجاد یک وظیفه جدید یا آوردن یک وظیفه موجود متفاوت به پیش‌زمینه است.

انتخاب توسعه‌دهنده برای محافظت‌های درون‌برنامه‌ای

این رفتار می‌تواند از SDK 37 به بعد فعال شود، شما باید صریحاً برای فعال کردن آن تصمیم بگیرید. این قابلیت برای جلوگیری از ربودن درون وظیفه (یا ساندویچ فعالیت ) طراحی شده است، که در آن یک برنامه مخرب می‌تواند یک فعالیت را در وظیفه برنامه شما اجرا کند تا آن را جعل هویت کرده و داده‌های کاربر را بدزدد.

فعال کردن محافظت‌ها

برای انتخاب و فعال کردن ASM برای برنامه خود، ویژگی android:allowCrossUidActivitySwitchFromBelow را در فایل AndroidManifest.xml خود روی false تنظیم کنید. این یک تنظیم در سطح برنامه است که به طور پیش‌فرض از تمام فعالیت‌های برنامه شما محافظت می‌کند.

ایجاد استثنا برای فعالیت‌های خاص

اگر آن را برای برنامه خود فعال کرده‌اید اما نیاز دارید که به یک فعالیت خاص و قابل اعتماد اجازه دهید توسط برنامه‌های دیگر راه‌اندازی شود، می‌توانید یک استثنای هدفمند ایجاد کنید. برای مستثنی کردن یک فعالیت واحد از این حفاظت، تابع setAllowCrossUidActivitySwitchFromBelow(true) را در متد onCreate() آن فعالیت فراخوانی کنید. این کار به آن فعالیت اجازه می‌دهد تا راه‌اندازی شود در حالی که بقیه برنامه شما محافظت شده باقی می‌ماند.

عیب‌یابی

برای یافتن پیام‌های مرتبط با استفاده از یک عبارت منظم، Logcat را فیلتر کنید. برچسب ActivityTaskManager اغلب استفاده می‌شود و فیلتر کردن بر اساس ActivityTaskManager می‌تواند به جداسازی گزارش‌ها کمک کند.

درک پیام‌های لاگ کلیدی

راه‌اندازی مسدود شده (خطا) : این پیام نشان می‌دهد که شروع فعالیت مسدود شده است.

  • معنی : شروع یک فعالیت رد شد زیرا گزینه لازم برای PendingIntent از طرف فرستنده (با هدف SDK 34+) یا سازنده (با هدف SDK 35+) وجود نداشت.
  • اقدام : شما باید کد خود را به‌روزرسانی کنید تا گزینه‌ی انتخاب صحیح ActivityOptions را شامل شود.

هنگام تجزیه و تحلیل لاگ‌ها، این فیلدها را بررسی کنید:

  • realCallingPackage : برنامه‌ای که PendingIntent را ارسال کرده است. این فرستنده است.
  • callingPackage : برنامه‌ای که PendingIntent را ایجاد کرده است. این creator است.

حالت سختگیرانه

با شروع از اندروید ۱۶، توسعه‌دهنده برنامه می‌تواند حالت Strict را فعال کند تا هنگام مسدود شدن راه‌اندازی یک فعالیت (یا در معرض خطر مسدود شدن هنگام راه‌اندازی SDK هدف برنامه) مطلع شود.

کد نمونه‌ای که باید از همان ابتدا در متد Application.onCreate() در برنامه، فعالیت یا سایر اجزای برنامه فعال شود:

override fun onCreate(savedInstanceState: Bundle?) {
     super.onCreate(savedInstanceState)
     StrictMode.setVmPolicy(
         StrictMode.VmPolicy.Builder()
         .detectBlockedBackgroundActivityLaunch()
         .penaltyLog()
         .build());
     )
 }