Безопасность деятельности

Android защищает пользователей от вредоносных приложений и обеспечивает надежный пользовательский интерфейс. Структура безопасности Activity Security включает в себя правила и ограничения платформы. Эти правила и ограничения предотвращают нежелательные прерывания работы интерфейса, перехват задач и другие угрозы безопасности. Эти угрозы связаны с тем, когда и как компоненты приложения отображаются на экране. Ключевым компонентом этой структуры является ограничение запуска действий из фонового режима.

Ограничения на запуск фоновой активности

Запуск фоновой активности (BAL) происходит, когда приложение, не находящееся на переднем плане, не имеющее видимых действий или получившее PendingIntent от другого приложения, пытается запустить новую активность. Это и есть запуск фоновой активности (BAL). Хотя существуют и законные сценарии использования, например, запуск приложения-будильника, неограниченный запуск фоновой активности приводит к ухудшению пользовательского опыта и созданию уязвимостей в системе безопасности.

Почему им установлены ограничения?

Начиная с Android 10 (уровень API 29), платформа ввела ограничения на запуск приложениями фоновых процессов. Эти меры защиты помогают предотвратить вредоносное поведение приложений и улучшить пользовательский опыт, снижая вероятность распространенных злоупотреблений, в том числе:

  • Перехват пользовательского интерфейса и всплывающая реклама : фоновое приложение неожиданно запускает активность (часто рекламу) поверх приложения, с которым пользователь взаимодействует в данный момент, перехватывая его сессию.
  • Фишинг и выдача себя за другое приложение: фоновое приложение запускает активность, которая имитирует другое приложение (например, поддельный экран входа в систему для легитимного приложения), чтобы украсть учетные данные пользователя. Часто это достигается с помощью атаки типа «Activity Sandwich», когда вредоносная активность внедряется в стек задач легитимного приложения.
  • Tapjacking : фоновое приложение отображает прозрачную или скрытую активность поверх другого приложения, чтобы перехватить нажатия пользователя и обманом заставить его совершить непреднамеренные действия.
  • Пробуждение приложения : фоновый компонент одного приложения активирует активные компоненты другого приложения, чтобы незаконным образом повысить показатели ежедневной активности пользователей.

Сервисы переднего плана (для выполнения текущих задач)

Если вашему приложению необходимо выполнять длительную задачу в фоновом режиме, о которой пользователь должен знать, например, воспроизведение музыки или отслеживание тренировки, вам следует использовать службу переднего плана . Служба переднего плана должна отображать постоянное уведомление, которое пользователь не может закрыть. Это уведомление может содержать интерактивные элементы управления (например, кнопки воспроизведения/паузы для музыкального приложения). Это позволяет пользователю быть в курсе и контролировать ситуацию, но не прерывает его полноэкранную активность.

Следуя этой иерархии — начиная со стандартных уведомлений и переходя к более навязчивым вариантам только при необходимости, — вы создадите более качественный и предсказуемый пользовательский опыт.

Когда запуск фоновой активности разрешен (исключения)

Приложение может запустить активность в фоновом режиме, если выполняется одно из следующих условий:

  • В приложении есть видимое окно, например, окно с активностью на переднем плане.
  • В настоящее время приложение представляет собой редактор методов ввода (IME).
  • Действие запускается из объекта PendingIntent , отправленного системой (например, при нажатии на уведомление).
  • Приложение имеет разрешение SYSTEM_ALERT_WINDOW , предоставленное пользователем.
  • Приложению предоставлено разрешение START_ACTIVITIES_FROM_BACKGROUND .
  • Приложение подключено к сервису, которому предоставлено разрешение на запуск фоновых процессов.
  • Запуск инициируется основным приложением устройства, например, когда пользователь нажимает на значок приложения или взаимодействует с виджетом.
  • Запуск происходит из ключевой части операционной системы, которая должна работать постоянно, например, служба телефонии, запускающая отображение экрана входящего вызова.

Новые меры по повышению безопасности и обязательные условия согласия.

Для дальнейшего повышения безопасности Android ввел более строгие правила, требующие явного согласия для приложений, использующих PendingIntent и IntentSender для запуска действий. Запуск разрешен только в том случае, если либо приложение, создавшее PendingIntent , либо приложение, отправившее его, дало согласие на предоставление ему прав на запуск в фоновом режиме.

В большинстве случаев, согласие на использование функции PendingIntent следует проявлять в приложении , отправляющем это событие, поскольку обычно именно с ним пользователь взаимодействует напрямую (например, нажимая кнопку).

Отправители должны дать согласие на использование функции PendingIntent.

Если ваше приложение ориентировано на Android 14 (уровень API 34) или выше, оно больше не предоставляет свои привилегии BAL по умолчанию при отправке PendingIntent . Если вы явно не дадите на это согласие, запуск активности может быть заблокирован , если создатель PendingIntent еще не предоставил свои собственные привилегии.

Для обеспечения успешного запуска отправитель должен предоставить свои привилегии, вызвав метод ActivityOptions.setPendingIntentBackgroundActivityStartMode() , при этом рекомендуемый режимActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_IF_VISIBLE (добавлен в SDK 36).

Это более строгий и безопасный режим. Он предоставляет разрешение только в том случае, если отправляющее приложение видно на экране в момент отправки PendingIntent . Это более надежно гарантирует, что запуск активности является прямым результатом взаимодействия пользователя с вашим приложением.

Таблица ожидающих намерений
Рисунок 1: Схема принятия решений при запуске фоновых процессов.

Используйте 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.

Если ваше приложение ориентировано на Android 15 (уровень 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 , на него распространяются аналогичные требования по согласию пользователя.

  • Начиная с Android 14 (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())
  • Начиная с Android 17 (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())

Схема последовательности: Ограничения БАЛ

Таблица ожидающих намерений
Рисунок 2: Процесс безопасного запуска активности с использованием PendingIntent.

Эта диаграмма иллюстрирует процесс безопасного запуска активности с помощью PendingIntent. Успешный запуск зависит от наличия действительной цепочки привилегий, в которой как минимум одно из участвующих приложений одновременно предоставляет свои привилегии и имеет возможность запускать активность из фонового режима.

  1. Создание и делегирование (Приложение A - Создатель)
    1. Приложение Creator формирует PendingIntent
    2. При использовании SDK 35+ создатель должен явно делегировать свои привилегии BAL с помощью метода setPendingIntentCreatorBackgroundActivityStartMode(), если он хочет, чтобы его привилегии использовались. По умолчанию привилегии не делегируются.
    3. Затем PendingIntent передается другому приложению (Приложению B).
  2. Запуск и вклад (Приложение B - Отправитель)
    1. Позже приложение-отправитель инициирует запуск, вызывая метод PendingIntent.send() .
    2. При использовании SDK 34+ отправитель должен явно указать свои собственные привилегии с помощью метода setPendingIntentBackgroundActivityStartMode(), если он хочет, чтобы его привилегии были использованы. По умолчанию привилегии не делегируются.
  3. Проверка безопасности системы Android
    1. Система Android перехватывает запрос на запуск и выполняет проверку безопасности.
    2. Он оценивает два условия:
    3. Передал ли создатель свои привилегии, И соответствует ли приложение создателя в настоящее время одному из общих исключений BAL?
    4. Предоставил ли отправитель свои привилегии, И соответствует ли текущее состояние приложения отправителя одному из общих исключений BAL?
  4. Исход
    1. РАЗРЕШЕНО : Если выполняется хотя бы одно из двух условий шага 3, цепочка привилегий проверяется. Система Android запускает целевое действие, и отправитель получает успешный результат.
    2. ЗАБЛОКИРОВАНО : если ни одно из условий не выполняется, система блокирует запуск. Приложение-отправитель не получает прямого возвращаемого значения или исключения, указывающего на сбой. Вместо этого система Android внутренне регистрирует сообщение « Запуск фоновой активности заблокирован! » в Logcat, которое разработчики должны проверять для отладки.

Предотвращение перехвата задач

Для предотвращения атак с перехватом задач (например, «Activity Sandwich») в Android 15 введены новые правила для приложений, использующих API уровня 37 или выше.

  • Правило 1 : В рамках одной задачи действие может быть запущено только другим действием, принадлежащим тому же приложению (то есть имеющим тот же UID), что и текущее самое верхнее действие в задаче.
  • Правило 2 : Только действие в рамках задачи на переднем плане, соответствующее UID самого верхнего действия, может создавать новую задачу или выводить на передний план другую, уже существующую задачу.

Возможность включения защиты во время выполнения задачи по желанию разработчика

Это поведение можно включить, начиная с целевого SDK 37; для этого необходимо явно дать согласие. Оно предназначено для предотвращения перехвата задач (или «песочницы активности »), когда вредоносное приложение может запустить активность внутри задачи вашего приложения, чтобы выдать себя за него и украсть данные пользователя.

Включение защиты

Чтобы включить ASM для вашего приложения, установите атрибут android:allowCrossUidActivitySwitchFromBelow в значение false в файле AndroidManifest.xml . Это настройка уровня приложения, которая по умолчанию защищает все действия в вашем приложении.

Создание исключений для конкретных действий

Если вы включили эту функцию для своего приложения, но вам необходимо разрешить запуск определенного доверенного действия другими приложениями, вы можете создать целевое исключение. Чтобы исключить одно действие из этой защиты, вызовите метод setAllowCrossUidActivitySwitchFromBelow(true) в методе ` onCreate() этого действия. Это позволит запускать только это действие, в то время как остальная часть вашего приложения останется защищенной.

Поиск неисправностей

Используйте фильтр Logcat для поиска релевантных сообщений с помощью регулярного выражения. Часто используется тег ActivityTaskManager , и фильтрация по ActivityTaskManager может помочь выделить нужные записи в логах.

Понимание ключевых сообщений журнала

Запуск заблокирован (ошибка) : Это сообщение указывает на то, что запуск активности был заблокирован.

  • Значение : Запуск активности был отклонен, поскольку у отправителя (для SDK 34+) или у создателя (для SDK 35+) отсутствовало необходимое согласие PendingIntent .
  • Действие : Вам необходимо обновить свой код, чтобы включить правильную опцию включения ActivityOptions .

При анализе журналов проверьте следующие поля:

  • realCallingPackage : Приложение, отправившее PendingIntent . Это отправитель .
  • callingPackage : Приложение, создавшее PendingIntent . Это создатель .

Строгий режим

Начиная с Android 16, разработчик приложения может включить строгий режим, чтобы получать уведомления о блокировке запуска активности (или о риске блокировки при повышении уровня целевого SDK приложения).

Пример кода для включения этой функции на раннем этапе в методе Application.onCreate() вашего приложения, Activity или другого компонента приложения:

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