← Назад к вопросам

Как защищаются стандартные Intent в Android

2.7 Senior🔥 141 комментариев
#Android компоненты

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Защита стандартных Intent в Android

Intent — это фундаментальный механизм межкомпонентного взаимодействия (Inter-Process Communication, IPC) в Android. Поскольку через него передаются чувствительные данные и запускаются важные операции, защита Intent является критически важной. Система Android использует разрешения (permissions), фильтры Intent (Intent Filters) и ряд других механизмов для минимизации рисков.

Основные механизмы защиты

1. Система разрешений (Permissions)

Это основной механизм защиты. Приложение-отправитель (explicit Intent) или система (implicit Intent) проверяет, имеет ли приложение-получатель необходимые права.

  • Защита на стороне получателя (Receiver): Компонент (Activity, Service, BroadcastReceiver) в манифесте объявляет, какое разрешение требуется для его вызова.
    <activity
        android:name=".SecureActivity"
        android:permission="com.example.perm.SECURE_ACCESS" >
        <intent-filter> ... </intent-filter>
    </activity>
    
    Отправитель должен быть наделен этим разрешением (в `uses-permission`) или подписан тем же сертификатом, иначе вызов завершится ошибкой `SecurityException`.

  • Защита на стороне отправителя (Sender): При отправке Intent (чаще всего Broadcast Intent) отправитель может указать разрешение, которое должно быть у получателей.
    Intent broadcast = new Intent("com.example.MY_ACTION");
    sendBroadcast(broadcast, "com.example.perm.RECEIVE_BROADCAST");
    
    В этом случае только приложения, объявившие `com.example.perm.RECEIVE_BROADCAST`, смогут принять это широковещательное сообщение.

2. Экспорт компонентов и Intent Filters

Атрибут android:exported в манифесте явно определяет, может ли компонент быть вызван извне (из других приложений).

  • exported="false": Компонент доступен только внутри своего приложения. Это самый безопасный вариант для внутренних компонентов.
  • exported="true" (явно или неявно): Компонент доступен извне. Неявно exported становится true, если у компонента объявлен <intent-filter>. Это создает потенциальную уязвимость, если фильтр слишком широкий.

Ключевая проблема: Небезопасные Implicit Intent с широкими фильтрами. Например, Activity с фильтром на ACTION_VIEW и CATEGORY_DEFAULT может быть случайно вызвана злоумышленником.

<!-- Потенциально небезопасно, если Activity не должна быть публичной -->
<activity android:name=".InternalViewerActivity" android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:mimeType="text/*" />
    </intent-filter>
</activity>

Защита: Всегда явно задавайте android:exported, сужайте фильтры насколько возможно, а для внутренних компонентов используйте Explicit Intent.

3. Защита данных Intent

Данные в Intent могут быть перехвачены.

  • Злонамеренные приложения, подписанные на те же Broadcast: Если Broadcast не защищен разрешением, его могут получить все.
  • Приложения с разрешением BIND_ACCESSIBILITY_SERVICE или через рутирование: Могут перехватывать UI-события.

Меры защиты:

  • Не передавайте чувствительные данные (пароли, токены) через неявные Intent или публичные Broadcast.
  • Используйте явные Intent для взаимодействия внутри своего приложения.
  • Для межпроцессного взаимодействия используйте защищенные разрешениями Broadcast, Content Providers с гранулярными permissions или Bound Services с проверкой вызывающей стороны.
  • Начиная с Android 12 (API 31), для компонентов с intent-filter необходимо явно объявлять android:exported.

4. Проверка вызывающей стороны (Caller Identity)

В точке получения Intent компонент может (и часто должен) проверить, кто его вызвал.

// В Activity, Service, BroadcastReceiver
public void onReceive(Context context, Intent intent) {
    // 1. Проверка через разрешение (система делает это автоматически)
    // 2. Дополнительная проверка пакета (для недоверенных источников)
    String callerPackage = getCallingPackage();
    if (callerPackage != null && !callerPackage.equals("trusted.package.name")) {
        return; // Игнорируем вызов
    }

    // 3. Проверка подписи (для взаимодействия между своими приложениями)
    if (getPackageManager().checkSignatures(callerPackage, getPackageName())
            == PackageManager.SIGNATURE_MATCH) {
        // Доверенный источник
    }
}

Рекомендации по безопасному использованию

  1. Минимизируйте использование exported="true". Компонент должен быть экспортирован, только если это функционально необходимо.
  2. Предпочитайте Explicit Intent Implicit. Для внутренней навигации всегда используйте явные интенты.
  3. Защищайте Broadcast Intent. Всегда используйте параметр разрешения в sendBroadcast() или устанавливайте android:permission в ресивере. Начиная с Android 8.0, для большинства событий используйте LocalBroadcastManager (устарел) или его аналог LiveData, Flow или LocalBroadcastManager из AndroidX.
  4. Не доверяйте данным входящего Intent. Всегда выполняйте валидацию и санацию входных данных (URI, extras).
  5. Используйте защищенные custom permissions. Сложные имена (com.company.app.permission.SPECIAL) снижают риск случайных коллизий.
  6. Для конфиденциальных данных используйте PendingIntent. Он делегирует права на выполнение операции системе, а не другому приложению.

Таким образом, защита стандартных Intent строится на комбинации декларативных правил в манифесте (permissions, exported) и программных проверок в коде. Безопасность достигается за счет принципа наименьших привилегий: компонент должен быть доступен минимально необходимому кругу вызывающих объектов и с минимально необходимыми правами.