Quyền truy cập mạng cục bộ

Mọi ứng dụng có quyền INTERNET đều có thể truy cập vào các thiết bị trong mạng cục bộ (LAN). Việc này giúp các ứng dụng dễ dàng kết nối với thiết bị cục bộ, nhưng cũng kéo theo những vấn đề về quyền riêng tư, chẳng hạn như việc tạo vân tay của người dùng và đóng vai trò là phương tiện gián tiếp để xác định vị trí.

Dự án Biện pháp bảo vệ mạng cục bộ nhằm mục đích bảo vệ quyền riêng tư của người dùng bằng cách kiểm soát quyền truy cập vào mạng cục bộ thông qua một quyền khi bắt đầu chạy mới.

Tác động

Kể từ Android 17 (cấp độ API 37), các biện pháp bảo vệ mạng cục bộ sẽ được thực thi cho các ứng dụng nhắm đến Android 17 trở lên. Cấu hình chọn sử dụng Android 16 trước đây không còn được dùng nữa; hãy xem phần Thực thi Android 17 để biết các yêu cầu triển khai hiện tại.

Ứng dụng sẽ bị ảnh hưởng nếu truy cập vào mạng cục bộ của người dùng bằng:

  • Sử dụng trực tiếp hoặc sử dụng thư viện của các cổng thô trên địa chỉ mạng cục bộ, ví dụ: Multicast DNS (mDNS) hoặc Simple Service Discovery Protocol (SSDP).
  • Sử dụng các lớp cấp khung truy cập vào mạng cục bộ, ví dụ: NsdManager.

Thông tin chi tiết về tác động

Lưu lượng truy cập đến và đi từ một địa chỉ mạng cục bộ cần có quyền truy cập mạng cục bộ. Bảng sau đây liệt kê một số trường hợp phổ biến:

Thao tác mạng cấp thấp của ứng dụng Cần có quyền truy cập mạng cục bộ
Tạo kết nối TCP đi có
Chấp nhận kết nối TCP đến có
Gửi một gói UDP đơn hướng, đa hướng, truyền phát có
Nhận một gói tin UDP unicast, multicast, broadcast đến có

Những quy định hạn chế này được triển khai sâu trong bộ phần cứng và phần mềm mạng, do đó, chúng áp dụng cho tất cả API mạng. Điều này bao gồm các cổng kết nối được tạo trong nền tảng hoặc mã được quản lý, các thư viện mạng như Cronet và OkHttp, cũng như mọi API được triển khai dựa trên các thư viện đó. Để phân giải các dịch vụ trên mạng cục bộ có hậu tố .local, bạn cần có quyền truy cập vào mạng cục bộ.

Các trường hợp ngoại lệ đối với quy tắc trước:

  • Nếu máy chủ DNS của thiết bị nằm trên mạng cục bộ, thì lưu lượng truy cập đến/từ máy chủ đó (tại cổng 53) không cần quyền truy cập mạng cục bộ.
  • Các ứng dụng sử dụng Trình chuyển đổi đầu ra làm bộ chọn trong ứng dụng sẽ không cần quyền truy cập vào mạng cục bộ (chúng tôi sẽ cung cấp thêm hướng dẫn trong một bản phát hành sau).

Thực thi Android 17

Kể từ Android 17, các biện pháp bảo vệ mạng cục bộ là bắt buộc và được thực thi cho các ứng dụng nhắm đến Android 17 trở lên.

Tỷ lệ Android 16 Android 17
SDK mục tiêu 36 37 trở lên
Quyền Đã tạm thời sử dụng NEARBY_WIFI_DEVICES ACCESS_LOCAL_NETWORK
Quyền truy cập mặc định Quyền truy cập mạng cục bộ đang mở Mạng cục bộ bị chặn theo mặc định đối với tất cả ứng dụng cập nhật SDK mục tiêu
Nhóm quyền Thuộc nhóm quyền NEARBY_DEVICES hiện có

Để xác minh rằng chức năng của ứng dụng không bị hỏng sau khi thực thi, các ứng dụng nhắm đến SDK 37 trở lên phải áp dụng một trong các đường dẫn sau để quản lý quyền truy cập vào mạng cục bộ:

Đường dẫn A: Sử dụng bộ chọn đảm bảo quyền riêng tư

Đối với các tác vụ kết nối và khám phá do hệ thống điều phối, hãy sử dụng bộ chọn để tránh yêu cầu quyền khi bắt đầu chạy trên diện rộng. Sử dụng các bộ chọn sau đây dựa trên trường hợp sử dụng của bạn:

  • Phát trực tuyến nội dung nghe nhìn: Các ứng dụng hỗ trợ Google Cast có thể sử dụng tính năng bộ chuyển đổi đầu ra. Nhờ đó, nhà phát triển có thể cho phép người dùng chọn các thiết bị phát trực tuyến cụ thể mà không cần ứng dụng yêu cầu quyền ACCESS_LOCAL_NETWORK rộng hơn.
  • Khả năng kết nối chung: NsdManager bao gồm một bộ chọn dịch vụ do hệ thống chạy để khám phá mDNS. Thay vì ứng dụng quét toàn bộ mạng, hệ thống sẽ hiển thị một hộp thoại cho phép người dùng chọn một thiết bị để ứng dụng truy cập.
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
    }
})

Cách B: Yêu cầu quyền khi bắt đầu chạy (quyền truy cập rộng)

Bạn cần có đường dẫn này cho các trường hợp sử dụng phức tạp như tự động hoá nhà hoặc quản lý thiết bị IoT cần quyền truy cập rộng và liên tục vào mạng cục bộ.

  • Khai báo quyền trong tệp kê khai: Khai báo rõ ràng ACCESS_LOCAL_NETWORK trong AndroidManifest.xml.

  • Yêu cầu cấp quyền trong thời gian chạy: Trước khi cố gắng truy cập vào mạng cục bộ, ứng dụng phải kiểm tra xem quyền đã được cấp hay chưa. Nếu không, họ phải gọi Activity.requestPermission() để kích hoạt lời nhắc hệ thống tiêu chuẩn.

  • Trường hợp được cấp trước: Quyền ACCESS_LOCAL_NETWORK thuộc nhóm quyền NEARBY_DEVICES. Nếu người dùng đã cấp một quyền khác trong nhóm này (chẳng hạn như quyền Bluetooth), thì họ sẽ không được nhắc lại về quyền truy cập vào mạng cục bộ.

  • Xử lý trường hợp từ chối và thu hồi: Ứng dụng phải xử lý linh hoạt các trường hợp người dùng từ chối yêu cầu hoặc sau đó thu hồi quyền trong phần cài đặt hệ thống. Trong những trường hợp như vậy, lưu lượng truy cập mạng cục bộ sẽ bị chặn.

Chiến lược đặt lại bộ đếm yêu cầu cấp quyền

Nền tảng này triển khai chiến lược đặt lại bộ đếm để giải quyết các trường hợp mà việc ứng dụng từ chối nhóm quyền NEARBY_DEVICES trước đó (hiện bao gồm ACCESS_LOCAL_NETWORK) ngăn ứng dụng yêu cầu quyền sau khi trình bày đầy đủ lý do. Cơ chế này cung cấp thêm cơ hội để ứng dụng gọi API requestPermission(), đặt lại số lần từ chối cho quyền ACCESS_LOCAL_NETWORK một cách hiệu quả. Điều này cho phép tương tác lại với người dùng một cách tinh tế hơn, đặc biệt là khi người dùng từ chối ban đầu trước khi ứng dụng có thể truyền đạt sự cần thiết của quyền truy cập vào mạng cục bộ đối với chức năng cốt lõi của ứng dụng.

Mô hình quản lý quyền phân tách

Quyền truy cập mạng cục bộ sử dụng chiến lược di chuyển quyền phân tách để xử lý các ứng dụng mới và ứng dụng cũ theo cách khác nhau, dựa trên SDK mục tiêu của các ứng dụng đó

Danh mục Cấp SDK mục tiêu Hành vi truy cập mạng cục bộ Việc cần làm đối với nhà phát triển
Ứng dụng mới/Ứng dụng đã cập nhật >= 37 (Android 17) Bị chặn theo mặc định Khai báo và yêu cầu quyền khi bắt đầu chạy ACCESS_LOCAL_NETWORK
Ứng dụng cũ < 37 Các ứng dụng có quyền INTERNET sẽ được cấp quyền ngầm ẩn cho ACCESS_LOCAL_NETWORK, cho phép các ứng dụng đó duy trì quyền truy cập. Đây là biện pháp tạm thời và sẽ bị chặn theo mặc định sau khi ứng dụng nâng SDK mục tiêu lên 37 Bạn không cần thay đổi mã ngay lập tức. Đừng yêu cầu ACCESS_LOCAL_NETWORK trong thời gian chạy trước khi nhắm đến SDK 37.

Chiến lược LNP theo trường hợp sử dụng

  • Truyền: Đối với các chức năng truyền nội dung nghe nhìn, chiến lược phù hợp nhất và đảm bảo quyền riêng tư là sử dụng trình chuyển đổi đầu ra. Phương thức này cho phép hệ thống thay mặt người dùng xử lý việc khám phá và kết nối mạng cục bộ, nhờ đó ứng dụng không cần yêu cầu quyền ACCESS_LOCAL_NETWORK.

  • Trình duyệt: Việc xử lý lỗi đòi hỏi các phương pháp khác nhau dựa trên giao thức. Lỗi UDP dẫn đến mã lỗi EPERM. Đối với kết nối TCP, trình duyệt nên sử dụng API NDK android_getnetworkblockedreason(int sockFd) để xác định xem một gói có bị LNP chặn hay không. API này trả về ANDROID_NETWORK_BLOCKED_REASON_LNP.

  • Các trường hợp sử dụng khác (ví dụ: IoT): Các ứng dụng tìm thiết bị bằng mDNS nên sử dụng android.net.nsd.DiscoveryRequest#FLAG_SHOW_PICKER để tìm thiết bị mà không cần quyền, và NsdManager#registerServiceInfoCallback / NsdManager#resolveService để lấy địa chỉ IP. Kết nối với địa chỉ IP có được theo cách này không yêu cầu quyền ACCESS_LOCAL_NETWORK.

Đối với các ứng dụng yêu cầu giao tiếp trực tiếp qua mạng cục bộ và không thể sử dụng bộ chọn do hệ thống điều phối, bạn nên sử dụng chiến lược đặt lại bộ đếm quyền khi nhắm đến Android 17 (SDK 37) trở lên. Nếu người dùng thu hồi quyền ACCESS_LOCAL_NETWORK, thì cơ chế này sẽ cung cấp thêm cơ hội để ứng dụng yêu cầu cấp lại quyền, cho phép nhà phát triển đưa ra lý do rõ ràng hơn cho người dùng.

Hướng dẫn về Android 16 (không dùng nữa)

Để chọn áp dụng các quy định hạn chế về mạng cục bộ trên Android 16, hãy làm như sau:

  1. Cài đặt ROM thiết bị của bạn vào một bản dựng chạy Android 16 Beta 3 trở lên
  2. Cài đặt ứng dụng cần kiểm thử
  3. Bật/tắt cấu hình Appcompat bằng adb

    adb shell am compat enable RESTRICT_LOCAL_NETWORK <package_name>
    
  4. Khởi động lại thiết bị

Giờ đây, quyền truy cập của ứng dụng vào mạng cục bộ bị hạn chế và mọi nỗ lực truy cập vào mạng cục bộ đều dẫn đến lỗi ổ cắm. Nếu bạn đang sử dụng các API thực hiện thao tác mạng cục bộ bên ngoài quy trình ứng dụng (ví dụ: NsdManager), thì các API đó sẽ không bị ảnh hưởng trong quá trình chọn sử dụng.

Để khôi phục quyền truy cập, bạn phải cấp cho ứng dụng quyền NEARBY_WIFI_DEVICES.

  • Đảm bảo ứng dụng khai báo quyền NEARBY_WIFI_DEVICES trong manifest.
  • Chuyển đến phần Cài đặt > Ứng dụng > [Tên ứng dụng] > Quyền > Thiết bị ở gần > Cho phép

Giờ đây, quyền truy cập của ứng dụng vào mạng cục bộ sẽ được khôi phục và tất cả các tình huống của bạn sẽ hoạt động như trước khi chọn sử dụng ứng dụng. Sau đây là ảnh hưởng đối với lưu lượng truy cập mạng của ứng dụng.

Quyền Yêu cầu LAN đi Yêu cầu Internet đi/đến Yêu cầu đến từ mạng LAN
Đã cấp Works Works Works
Chưa được cấp Thất bại Works Thất bại

Sử dụng lệnh sau để tắt cấu hình Appcompat

adb shell am compat disable RESTRICT_LOCAL_NETWORK <package_name>

Lỗi

Nếu yêu cầu truy cập vào mạng cục bộ không thành công do thiếu quyền:

  • Kết nối TCP thường sẽ dẫn đến lỗi hết thời gian chờ.

  • Lỗi UDP và lỗi từ chối cấp quyền chung thường dẫn đến mã lỗi EPERM

Lỗi

Gửi lỗi và ý kiến phản hồi về:

  • Sự khác biệt về quyền truy cập vào mạng LAN (bạn cho rằng một quyền truy cập nhất định không nên được coi là quyền truy cập vào "mạng cục bộ")
  • Lỗi khiến quyền truy cập vào mạng LAN không bị chặn dù đáng lẽ phải bị chặn
  • Lỗi khiến quyền truy cập vào mạng LAN bị chặn dù không nên bị chặn

Thay đổi này sẽ không ảnh hưởng đến những quyền sau đây:

  • Quyền truy cập Internet
  • Mạng di động