Разрешение на доступ к локальной сети

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

Проект "Защита локальной сети" направлен на защиту конфиденциальности пользователей. Для этого мы ограничиваем доступ к локальной сети с помощью нового динамического разрешения.

Влияние

Начиная с Android 17 (уровень API 37), защита локальной сети применяется к приложениям, предназначенным для Android 17 или более поздней версии. Прежняя конфигурация Android 16 больше не поддерживается. Ознакомьтесь с требованиями к реализации для Android 17.

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

  • Прямое или библиотечное использование необработанных сокетов на адресах локальной сети, например Multicast DNS (mDNS) или Simple Service Discovery Protocol (SSDP).
  • Использование классов на уровне фреймворка, которые обращаются к локальной сети, например NsdManager.

Сведения о последствиях

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

Низкоуровневая сетевая операция приложения Требуется разрешение на доступ к локальной сети
Установление исходящего TCP-соединения Да
Принятие входящего TCP-подключения Да
Отправка одноадресного, многоадресного или широковещательного UDP-пакета. Да
Получение входящих одноадресных, многоадресных и широковещательных UDP-пакетов. Да

Эти ограничения реализованы на уровне сетевого стека и поэтому применяются ко всем сетевым API. Это касается сокетов, созданных на платформе или в управляемом коде, сетевых библиотек, таких как Cronet и OkHttp, и любых API, реализованных на их основе. Чтобы разрешить сервисы в локальной сети, у которых есть суффикс .local, требуется разрешение на доступ к локальной сети.

Исключения из предыдущих правил:

  • Если DNS-сервер устройства находится в локальной сети, для трафика к нему и от него (через порт 53) не требуется разрешение на доступ к локальной сети.
  • Приложениям, в которых переключатель вывода используется для выбора устройства, не потребуются разрешения на доступ к локальной сети (подробные инструкции будут опубликованы в одном из следующих выпусков).

Принудительное применение Android 17

Начиная с Android 17 защита локальной сети обязательна и применяется к приложениям, предназначенным для Android 17 или более поздней версии.

Формат Android 16 Android 17
Целевой SDK 36 37 или выше
Разрешение Временно используется разрешение NEARBY_WIFI_DEVICES ACCESS_LOCAL_NETWORK
Доступ по умолчанию Доступ к локальной сети открыт Локальная сеть по умолчанию заблокирована для всех приложений, которые обновляют целевой SDK.
Группа разрешений Входит в существующую группу разрешений NEARBY_DEVICES.

Чтобы убедиться, что функции приложения не нарушены после применения мер, приложения, использующие SDK 37 или более поздней версии, должны использовать один из следующих способов управления доступом к локальной сети:

Путь А. Использование инструментов выбора, обеспечивающих конфиденциальность

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

  • Потоковая передача медиаконтента. В приложениях с поддержкой Google Cast можно использовать переключатель вывода медиаданных. Это позволяет разработчикам разрешать пользователям выбирать определенные устройства потоковой передачи без необходимости запрашивать у приложения разрешение ACCESS_LOCAL_NETWORK.
  • Общие возможности подключения. В NsdManager есть системный инструмент выбора сервисов для обнаружения mDNS. Вместо того чтобы приложение сканировало всю сеть, система показывает диалоговое окно, в котором пользователь может выбрать одно устройство, к которому приложение получит доступ.
val discoveryRequest = DiscoveryRequest.Builder("_http._tcp")
    .setFlags(DiscoveryRequest.FLAG_SHOW_PICKER)
    .build()

nsdManager.registerServiceInfoCallback(discoveryRequest, executor, object : NsdManager.ServiceInfoCallback {
    override fun onServiceUpdated(serviceInfo: NsdServiceInfo) {
        // Handle the user-selected and discovered service
        // NsdServiceInfo.getHostAddresses() can now be connected to
        // without ACCESS_LOCAL_NETWORK permission
    }
})

Вариант Б. Запрос динамического разрешения (широкий доступ)

Этот путь необходим для сложных сценариев использования, таких как автоматизация дома или управление устройствами IoT, для которых требуется широкий и постоянный доступ к локальной сети.

  • Объявите разрешение в манифесте. Явно объявите ACCESS_LOCAL_NETWORK в файле AndroidManifest.xml.

  • Запрашивайте разрешение во время выполнения. Прежде чем пытаться получить доступ к локальной сети, приложения должны проверить, предоставлено ли разрешение. В противном случае необходимо вызвать Activity.requestPermission(), чтобы запустить стандартную системную подсказку.

  • Разрешение предоставлено заранее. Разрешение ACCESS_LOCAL_NETWORK входит в группу разрешений NEARBY_DEVICES. Если пользователь уже предоставил другое разрешение в этой группе (например, разрешение на использование Bluetooth), он не будет повторно запрашивать доступ к локальной сети.

  • Обработка отказа и отзыва. Приложения должны корректно обрабатывать случаи, когда пользователь отклоняет запрос или позже отзывает разрешение в системных настройках. В таких случаях трафик локальной сети будет заблокирован.

Стратегия сброса счетчика запросов разрешений

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

Раздельная модель разрешений

Для разрешения на доступ к локальной сети используется стратегия разделения разрешений, чтобы по-разному обрабатывать новые и устаревшие приложения в зависимости от целевого SDK.

Категория Целевой уровень SDK Режим работы доступа к локальной сети Что нужно сделать разработчику
Новые и обновленные приложения >= 37 (Android 17) Заблокировано по умолчанию Объявите и запросите динамическое разрешение ACCESS_LOCAL_NETWORK
Устаревшие приложения < 37 Приложения с разрешением INTERNET получают неявное разрешение ACCESS_LOCAL_NETWORK, которое позволяет им сохранять доступ. Это временная мера. Когда целевой SDK приложения будет обновлен до версии 37, доступ будет заблокирован по умолчанию. Изменять код прямо сейчас не требуется. Не запрашивайте разрешение ACCESS_LOCAL_NETWORK во время выполнения, если вы не используете SDK 37.

Стратегия LNP по вариантам использования

  • Трансляция. Для трансляции медиаконтента лучше всего использовать переключатель вывода, так как он обеспечивает конфиденциальность. Этот метод позволяет системе обнаруживать локальные сети и подключаться к ним от имени пользователя, поэтому приложению не нужно запрашивать разрешение ACCESS_LOCAL_NETWORK.

  • Браузеры. Обработка ошибок требует разных подходов в зависимости от протокола. Ошибки UDP приводят к коду ошибки EPERM. Для TCP-подключений браузеры должны использовать NDK API android_getnetworkblockedreason(int sockFd), чтобы определить, был ли пакет заблокирован LNP. Этот API возвращает ANDROID_NETWORK_BLOCKED_REASON_LNP.

  • Другие сценарии использования (например, интернет вещей). Приложения, которые находят устройства с помощью mDNS, должны использовать android.net.nsd.DiscoveryRequest#FLAG_SHOW_PICKER, чтобы находить устройства без разрешения, и NsdManager#registerServiceInfoCallback/NsdManager#resolveService, чтобы получать IP-адреса. Для подключения к IP-адресам, полученным таким образом, разрешение ACCESS_LOCAL_NETWORK не требуется.

Если приложению требуется прямая связь по локальной сети и оно не может использовать системные инструменты выбора, рекомендуем использовать стратегию сброса счетчика разрешений для Android 17 (SDK 37) или более поздней версии. Если пользователь отзовет разрешение ACCESS_LOCAL_NETWORK, этот механизм позволит приложению запросить его повторно, а разработчикам – объяснить пользователю, зачем оно нужно.

Руководство по Android 16 (устарело)

Чтобы включить ограничения локальной сети в Android 16, выполните следующие действия:

  1. Прошейте устройство сборкой с Android 16 Beta 3 или более поздней версией
  2. Установите приложение, которое нужно протестировать.
  3. Как переключить конфигурацию Appcompat с помощью adb

    adb shell am compat enable RESTRICT_LOCAL_NETWORK <package_name>
    
  4. Перезагрузить устройство

Теперь доступ приложения к локальной сети ограничен, и любая попытка получить его приводит к ошибкам сокета. Если вы используете API, которые выполняют операции в локальной сети вне процесса приложения (например, NsdManager), то они не будут затронуты во время согласия.

Чтобы восстановить доступ, предоставьте приложению разрешение на NEARBY_WIFI_DEVICES.

  • Убедитесь, что в файле manifest приложения объявлено разрешение NEARBY_WIFI_DEVICES.
  • Выберите Настройки > Приложения > [Название приложения] > Разрешения > Устройства поблизости > Разрешить.

Теперь доступ приложения к локальной сети должен быть восстановлен, а все сценарии должны работать так же, как и до включения приложения. Вот как это влияет на сетевой трафик приложения.

Разрешение Исходящий запрос LAN Исходящий/входящий интернет-запрос Входящий запрос в локальной сети
Разрешения даны YouTube YouTube YouTube
Доступ не предоставлен Глупые и смешные YouTube Глупые и смешные

Чтобы отключить конфигурацию Appcompat, используйте следующую команду:

adb shell am compat disable RESTRICT_LOCAL_NETWORK <package_name>

Ошибки

Если запрос на доступ к локальной сети не выполняется из-за отсутствия разрешения:

  • При подключении по протоколу TCP обычно возникает ошибка, связанная с истечением времени ожидания.

  • Ошибки UDP и общий отказ в разрешениях обычно приводят к коду ошибки EPERM.

Ошибки

Сообщайте об ошибках и оставляйте отзывы о следующих продуктах:

  • Расхождения в доступе к локальной сети (вы считаете, что определенный доступ не должен считаться доступом к локальной сети).
  • Ошибки, из-за которых доступ к локальной сети не блокируется, хотя должен.
  • Ошибки, из-за которых доступ к LAN блокируется, когда этого не должно происходить.

Изменение не затронет:

  • доступ к интернету;
  • Мобильная сеть