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

ローカルエリア ネットワーク(LAN)上のデバイスには、INTERNET 権限を持つすべてのアプリがアクセスできます。これにより、アプリはローカル デバイスに簡単に接続できるようになりますが、ユーザーのフィンガープリントが作成されたり、位置情報が推測されたりするなど、プライバシー上の懸念も生じます。

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

影響

Android 17(API レベル 37)以降では、Android 17 以降を対象とするアプリにローカル ネットワーク保護が適用されます。以前の Android 16 のオプトイン構成は非推奨になりました。現在の実装要件については、Android 17 の適用をご覧ください。

以下を使用してユーザーのローカル ネットワークにアクセスするアプリが影響を受けます。

  • ローカル ネットワーク アドレス(Multicast DNS (mDNS) や Simple Service Discovery Protocol (SSDP) など)での raw ソケットの直接使用またはライブラリ使用。
  • ローカル ネットワークにアクセスするフレームワーク レベルのクラス(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.xml で ACCESS_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 に引き上げると、デフォルトでブロックされます。 今すぐコードを変更する必要はありません。SDK 37 をターゲットとする前に、実行時に ACCESS_LOCAL_NETWORK をリクエストしないでください。

ユースケース別の 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 権限は必要ありません。

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

Android 16 のガイダンス(非推奨)

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 への権限を付与する必要があります。

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

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

権限 送信 LAN リクエスト アウトバウンド / インバウンドのインターネット リクエスト 受信 LAN リクエスト
許可 取り組み 取り組み 取り組み
不付与 ハプニング集 取り組み ハプニング集

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

adb shell am compat disable RESTRICT_LOCAL_NETWORK <package_name>

エラー

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

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

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

バグ

以下に関するバグやフィードバックを送信します。

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

以下は、この変更の影響を受けないはずです。

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