ローカル ネットワークへのアクセス権

ローカル エリア ネットワーク(LAN)上のデバイスには、INTERNET 権限を持つアプリからアクセスできます。これにより、アプリはローカル デバイスに簡単に接続できますが、ユーザーのフィンガープリントの作成や位置情報のプロキシなど、プライバシーに関する影響もあります。

ローカル ネットワーク保護プロジェクトは、新しいランタイム権限によってローカル ネットワークへのアクセスを制限することで、ユーザーのプライバシーを保護することを目的としています。

影響

Android 16 では、この権限はオプトイン機能です。つまり、オプトインしたアプリのみが影響を受けます。オプトインの目的は、アプリのどの部分が暗黙的なローカル ネットワーク アクセスに依存しているかをアプリ デベロッパーが把握し、将来の Android リリースでそれらの部分の権限を保護する準備をできるようにすることです。

アプリが次の方法でユーザーのローカル ネットワークにアクセスする場合、アプリは影響を受けます。

  • ローカル ネットワーク アドレス(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 以上をターゲットとするアプリは、ローカル ネットワーク アクセスを管理するために次のいずれかの方法を採用する必要があります。

パス A: プライバシー保護のピッカーを使用する

システムが仲介する検出タスクと接続タスクでは、ピッカーを使用して、広範なランタイム権限のリクエストを完全に回避します。ユースケースに応じて、次のピッカーを使用します。

  • メディア ストリーミング: 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
    }
})

パス B: 実行時の権限(広範なアクセス)をリクエストする

このパスは、ローカル ネットワークへの広範で永続的なアクセスを必要とするスマートホームや IoT デバイス管理などの複雑なユースケースに必要です。

  • マニフェストで権限を宣言する: デベロッパーは、AndroidManifest.xmlACCESS_LOCAL_NETWORK を明示的に宣言する必要があります。

  • 実行時に権限をリクエストする: ローカル ネットワークへのアクセスを試みる前に、アプリは権限が付与されているかどうかを確認する必要があります。そうでない場合は、Activity.requestPermission() を呼び出して標準のシステム プロンプトをトリガーする必要があります。

  • 事前付与シナリオ: ACCESS_LOCAL_NETWORK 権限は NEARBY_DEVICES 権限グループに含まれます。ユーザーがこのグループの別の権限(Bluetooth 権限など)をすでに付与している場合、ローカル ネットワーク アクセスのプロンプトが再度表示されることはありません。

  • 拒否と取り消しの処理: ユーザーがリクエストを拒否した場合や、後でシステム設定で権限を取り消した場合、アプリは適切に処理する必要があります。このようなシナリオでは、ローカル ネットワーク トラフィックがブロックされます。

権限リクエストのリセット カウンタ戦略

プラットフォームは、アプリが NEARBY_DEVICES 権限グループ(現在は ACCESS_LOCAL_NETWORK を含む)を以前に拒否したことで、十分な理由を提示した後に権限をリクエストできなくなるシナリオに対応するカウンタ リセット戦略を実装しています。このメカニズムにより、アプリが requestPermission() API を呼び出す機会が増え、事実上 ACCESS_LOCAL_NETWORK 権限の拒否回数がリセットされます。これにより、特にアプリがコア機能でローカル ネットワーク アクセスが必要であることを伝える前に、ユーザーが最初に拒否した場合に、ユーザーとの再エンゲージメントをより細かく調整できます。

分割権限モデル

ローカル ネットワーク権限は、ターゲット SDK に基づいて新しいアプリと以前のアプリを別々に処理するために、分割権限移行戦略を利用します。

カテゴリ ターゲット SDK レベル ローカル ネットワーク アクセスの動作 デベロッパーに必要な対応
新着アプリ / 更新されたアプリ >= 37(Android 17) デフォルトでブロック ACCESS_LOCAL_NETWORK 実行時の権限を宣言してリクエストする
レガシーアプリ 37 未満 INTERNET 権限を持つアプリは 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 を返します。

  • その他のユースケース(IoT など): mDNS を使用してデバイスを検出するアプリは、権限なしでデバイスを検出できる android.net.nsd.DiscoveryRequest#FLAG_SHOW_PICKER と、IP アドレスを取得するための NsdManager#registerServiceInfoCallback / NsdManager#resolveService を使用する必要があります。この方法で取得した IP アドレスへの接続には、ACCESS_LOCAL_NETWORK 権限は必要ありません。

ローカル ネットワークでの直接通信が必要で、システム仲介型のピッカーを使用できないアプリでは、権限リセット カウンタ戦略を使用することをおすすめします。ユーザーによって ACCESS_LOCAL_NETWORK 権限が取り消された場合、このメカニズムにより、アプリが権限を再リクエストする機会が追加で提供され、デベロッパーはユーザーに対してより明確な理由を提示できます。

Android 16 のガイダンス

ローカル ネットワークの制限を有効にする手順は次のとおりです。

  1. Android 16 ベータ版 3 以降のビルドにデバイスをフラッシュする
  2. テスト対象のアプリをインストールする
  3. adb を使用して Appcompat 構成を切り替える

    adb shell am compat enable RESTRICT_LOCAL_NETWORK <package_name>
    
  4. デバイスを再起動する

これで、アプリのローカル ネットワークへのアクセスが制限され、ローカル ネットワークにアクセスしようとするとソケット エラーが発生します。アプリのプロセス外でローカル ネットワーク オペレーションを実行する API(NsdManager など)を使用している場合、オプトイン中に影響を受けることはありません。

アクセス権を復元するには、アプリに NEARBY_WIFI_DEVICES への権限を付与する必要があります。

  • アプリが manifestNEARBY_WIFI_DEVICES 権限を宣言していることを確認します。
  • [設定] > [アプリ] > [[アプリ名]] > [権限] > [付近のデバイス] > [許可] に移動します。

これで、アプリのローカル ネットワークへのアクセスが復元され、アプリを有効にする前と同じようにすべてのシナリオが動作するはずです。アプリのネットワーク トラフィックへの影響は次のとおりです。

権限 アウトバウンド LAN リクエスト アウトバウンド/インバウンドのインターネット リクエスト インバウンド LAN リクエスト
許可 Works Works Works
未許可 ハプニング集 Works ハプニング集

次のコマンドを使用して、AppCompat 構成をオフに切り替えます。

adb shell am compat disable RESTRICT_LOCAL_NETWORK <package_name>

エラー

権限がないためローカル ネットワーク アクセス リクエストが失敗した場合:

  • 通常、TCP 接続ではタイムアウト エラーが発生します。

  • 通常、UDP エラーと一般的な権限拒否は EPERM エラーコードになります。

バグ

以下のバグとフィードバックを送信します。

  • LAN アクセスの不一致(特定のアクセスが「ローカル ネットワーク」アクセスと見なされるべきではないと思われる場合)
  • LAN アクセスがブロックされるべきなのにブロックされないバグ
  • LAN アクセスがブロックされるべきではないのにブロックされるバグ

この変更の影響を受けないものは次のとおりです。

  • インターネットへのアクセス
  • モバイル ネットワーク