สิทธิ์เข้าถึงเครือข่ายภายใน

แอปใดก็ตามที่มีสิทธิ์ INTERNET จะเข้าถึงอุปกรณ์ในเครือข่าย LAN ได้ ซึ่งช่วยให้แอปเชื่อมต่อกับอุปกรณ์ในเครือข่ายภายในได้ง่าย แต่ก็มีผลกระทบต่อความเป็นส่วนตัวด้วย เช่น การสร้างลายนิ้วมือของผู้ใช้และการทำหน้าที่เป็นพร็อกซีสำหรับตำแหน่ง

โปรเจ็กต์การป้องกันเครือข่ายภายในมีเป้าหมายเพื่อปกป้องความเป็นส่วนตัวของผู้ใช้โดยการจำกัดการเข้าถึงเครือข่ายภายในด้วยสิทธิ์รันไทม์ใหม่

ผลกระทบ

ใน Android 16 สิทธิ์นี้เป็นฟีเจอร์ที่เลือกใช้ได้ ซึ่งหมายความว่าจะมีเฉพาะแอปที่เลือกใช้เท่านั้นที่จะได้รับผลกระทบ เป้าหมายของการเลือกใช้คือให้นักพัฒนาแอปเข้าใจว่าส่วนใดของแอปที่ต้องใช้การเข้าถึงเครือข่ายภายในโดยนัย เพื่อให้เตรียมพร้อมที่จะป้องกันสิทธิ์ใน Android เวอร์ชันต่อๆ ไปได้

แอปจะได้รับผลกระทบหากเข้าถึงเครือข่ายภายในของผู้ใช้โดยใช้สิ่งต่อไปนี้

  • การใช้ซ็อกเก็ตดิบโดยตรงหรือผ่านไลบรารีในที่อยู่เครือข่ายภายใน เช่น Multicast DNS (mDNS) หรือ Simple Service Discovery Protocol (SSDP)
  • การใช้คลาสระดับเฟรมเวิร์กที่เข้าถึงเครือข่ายภายใน เช่น NsdManager

รายละเอียดของผลกระทบ

การรับส่งข้อมูลไปยังและจากที่อยู่เครือข่ายภายในต้องใช้สิทธิ์เข้าถึงเครือข่ายภายใน ตารางต่อไปนี้แสดงกรณีที่พบบ่อยบางกรณี

App Low Level Network Operation Local Network Permission Required
Making an outgoing TCP connection ใช่
Accepting an incoming TCP connection ใช่
Sending a UDP unicast, multicast, broadcast ใช่
Receiving a incoming UDP unicast, multicast, broadcast ใช่

ข้อจำกัดเหล่านี้ได้รับการติดตั้งใช้งานในส่วนลึกของสแต็กเครือข่าย จึงมีผลกับ API เครือข่ายทั้งหมด ซึ่งรวมถึงซ็อกเก็ตที่สร้างขึ้นในแพลตฟอร์มหรือโค้ดที่มีการจัดการ ไลบรารีเครือข่าย เช่น Cronet และ OkHttp รวมถึง API ใดก็ตามที่ติดตั้งใช้งานบนไลบรารีเหล่านั้น การพยายามแก้ไขบริการในเครือข่ายภายในที่มีคำต่อท้าย .local ต้องใช้สิทธิ์เข้าถึงเครือข่ายภายใน

ข้อยกเว้นของกฎข้างต้น

  • หากเซิร์ฟเวอร์ DNS ของอุปกรณ์อยู่ในเครือข่ายภายใน การรับส่งข้อมูลไปยัง / จากเซิร์ฟเวอร์ (ที่พอร์ต 53) ไม่ต้องใช้สิทธิ์เข้าถึงเครือข่ายภายใน
  • แอปพลิเคชันที่ใช้ Output Switcher เป็นเครื่องมือเลือกในแอปจะไม่ต้องใช้สิทธิ์เข้าถึงเครือข่ายภายใน (คำแนะนำเพิ่มเติมจะมาในรุ่นต่อๆ ไป)

การบังคับใช้ใน Android 17

ตั้งแต่ Android 17 เป็นต้นไป การป้องกันเครือข่ายภายในเป็นสิ่งที่จำเป็นและมีการบังคับใช้กับแอปที่กำหนดเป้าหมายเป็น Android 17 ขึ้นไป

Aspect Android 16 Android 17
Target SDK 36 37 ขึ้นไป
Permission NEARBY_WIFI_DEVICES ที่ใช้ชั่วคราว ACCESS_LOCAL_NETWORK
Default Access การเข้าถึงเครือข่ายภายในเปิดอยู่ ระบบจะบล็อกเครือข่ายภายในโดยค่าเริ่มต้นสำหรับแอปทั้งหมดที่อัปเดต SDK เป้าหมาย
Permission Group เป็นส่วนหนึ่งของกลุ่มสิทธิ์ NEARBY_DEVICES ที่มีอยู่

หากต้องการยืนยันว่าฟังก์ชันการทำงานของแอปไม่เสียหายหลังจากการบังคับใช้ แอปพลิเคชันที่กำหนดเป้าหมายเป็น SDK 37 ขึ้นไปต้องใช้เส้นทางใดเส้นทางหนึ่งต่อไปนี้เพื่อจัดการการเข้าถึงเครือข่ายภายใน

เส้นทาง ก: การใช้เครื่องมือเลือกที่เน้นความเป็นส่วนตัว

สำหรับงานการค้นพบและการเชื่อมต่อที่ระบบเป็นสื่อกลาง ให้ใช้เครื่องมือเลือกเพื่อหลีกเลี่ยงการขอสิทธิ์รันไทม์แบบกว้างทั้งหมด ใช้เครื่องมือเลือกต่อไปนี้ตามกรณีการใช้งาน

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 ที่ต้องมีการเข้าถึงเครือข่ายภายในแบบกว้างและต่อเนื่อง

  • ประกาศสิทธิ์ในไฟล์ Manifest: ประกาศ ACCESS_LOCAL_NETWORK อย่างชัดเจนใน AndroidManifest.xml

  • ขอสิทธิ์ขณะรันไทม์: ก่อนที่จะพยายามเข้าถึงเครือข่ายภายใน แอปพลิเคชันต้องตรวจสอบว่าได้รับสิทธิ์แล้วหรือไม่ หากไม่ได้รับสิทธิ์ แอปพลิเคชันต้องเรียกใช้ Activity.requestPermission() เพื่อทริกเกอร์ข้อความแจ้งมาตรฐานของระบบ

  • สถานการณ์ที่ได้รับสิทธิ์ล่วงหน้า: สิทธิ์ ACCESS_LOCAL_NETWORK เป็นส่วนหนึ่ง ของกลุ่มสิทธิ์ NEARBY_DEVICES หากผู้ใช้ให้สิทธิ์อื่นในกลุ่มนี้แล้ว (เช่น สิทธิ์ Bluetooth) ระบบจะไม่แจ้งให้ขอสิทธิ์เข้าถึงเครือข่ายภายในอีก

  • การจัดการการปฏิเสธและการเพิกถอน: แอปต้องจัดการอย่างเหมาะสมในกรณีที่ผู้ใช้ปฏิเสธคำขอหรือเพิกถอนสิทธิ์ในภายหลังในการตั้งค่าระบบ ในสถานการณ์ดังกล่าว ระบบจะบล็อกการรับส่งข้อมูลเครือข่ายภายใน

กลยุทธ์ตัวนับรีเซ็ตคำขอสิทธิ์

แพลตฟอร์มใช้กลยุทธ์การรีเซ็ตตัวนับที่จัดการสถานการณ์ที่ การปฏิเสธกลุ่มสิทธิ์ NEARBY_DEVICES ก่อนหน้านี้ของแอป (ซึ่งตอนนี้รวมถึง ACCESS_LOCAL_NETWORK) ทำให้แอปขอ สิทธิ์ไม่ได้หลังจากแสดงเหตุผลอย่างเพียงพอแล้ว กลไกนี้ ให้โอกาสเพิ่มเติมแก่แอปในการเรียกใช้ API requestPermission() ซึ่งจะรีเซ็ตจำนวนการปฏิเสธสิทธิ์ ACCESS_LOCAL_NETWORK ซึ่งช่วยให้มีการกลับมามีส่วนร่วมกับผู้ใช้ในลักษณะที่ละเอียดมากขึ้น โดยเฉพาะอย่างยิ่งเมื่อการปฏิเสธครั้งแรกเกิดขึ้นก่อนที่แอปจะสื่อสารความจำเป็นในการเข้าถึงเครือข่ายภายในสำหรับฟังก์ชันหลักของแอปได้

โมเดลสิทธิ์แบบแยก

สิทธิ์เข้าถึงเครือข่ายภายในใช้กลยุทธ์การย้ายข้อมูลสิทธิ์แบบแยกเพื่อจัดการแอปพลิเคชันใหม่และแอปพลิเคชันเดิมแตกต่างกันไปตาม SDK เป้าหมาย

Category Target SDK level Local network access behavior Required developer action
New Apps / Updated Apps >= 37 (Android 17) Blocked By Default Declare and request ACCESS_LOCAL_NETWORK runtime permission
Legacy Apps < 37 Apps with INTERNET permission receive an implicit permission grant for ACCESS_LOCAL_NETWORK, allowing them to retain access. This is temporary and will be blocked by default once app bumps target SDK to 37 No immediate code change needed. Don't request ACCESS_LOCAL_NETWORK at runtime prior to targeting SDK 37.

กลยุทธ์ LNP ตามกรณีการใช้งาน

  • การแคสต์: สำหรับฟังก์ชันการทำงานของการแคสต์สื่อ กลยุทธ์ที่เหมาะสมที่สุดและ เน้นความเป็นส่วนตัวคือการใช้ Output Switcher วิธีนี้ ช่วยให้ระบบจัดการการค้นพบและการเชื่อมต่อเครือข่ายภายในในนามของผู้ใช้ ได้ จึงไม่จำเป็นต้องให้แอปขอสิทธิ์ 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 ซึ่งอนุญาตให้ค้นหาอุปกรณ์ได้โดยไม่ต้องมีสิทธิ์ และ NsdManager#registerServiceInfoCallback / NsdManager#resolveService เพื่อรับที่อยู่ IP การเชื่อมต่อกับที่อยู่ IP ที่ได้รับด้วยวิธีนี้ไม่จำเป็นต้องมีสิทธิ์ ACCESS_LOCAL_NETWORK

สำหรับแอปพลิเคชันที่ต้องมีการสื่อสารเครือข่ายภายในโดยตรงและไม่สามารถใช้เครื่องมือเลือกที่ระบบเป็นสื่อกลางได้ วิธีที่แนะนำคือใช้กลยุทธ์ตัวนับรีเซ็ตสิทธิ์เมื่อกำหนดเป้าหมายเป็น Android 17 (SDK 37) ขึ้นไป หากผู้ใช้เพิกถอนสิทธิ์ ACCESS_LOCAL_NETWORK กลไกนี้ จะให้โอกาสเพิ่มเติมแก่แอปในการขอสิทธิ์อีกครั้ง ซึ่งช่วยให้นักพัฒนาแอปแสดงเหตุผลที่ชัดเจนยิ่งขึ้นแก่ผู้ใช้ได้

คำแนะนำสำหรับ Android 16

หากต้องการเลือกใช้ข้อจำกัดเครือข่ายภายใน ให้ทำดังนี้

  1. แฟลชอุปกรณ์เป็นบิลด์ที่มี Android 16 Beta 3 ขึ้นไป
  2. ติดตั้งแอปที่จะทดสอบ
  3. สลับการกำหนดค่า Appcompat โดยใช้ adb

    adb shell am compat enable RESTRICT_LOCAL_NETWORK <package_name>
    
  4. รีบูตอุปกรณ์

ตอนนี้การเข้าถึงเครือข่ายภายในของแอปถูกจำกัดแล้ว และการพยายามเข้าถึงเครือข่ายภายในจะทำให้เกิดข้อผิดพลาดของซ็อกเก็ต หากคุณใช้ API ที่ดำเนินการเครือข่ายภายในนอกกระบวนการของแอป (เช่น NsdManager) API เหล่านี้จะไม่ได้รับผลกระทบระหว่างการเลือกใช้

หากต้องการคืนสิทธิ์เข้าถึง คุณต้องให้สิทธิ์ NEARBY_WIFI_DEVICES แก่แอป

  • ตรวจสอบว่าแอปประกาศสิทธิ์ NEARBY_WIFI_DEVICES ใน manifest
  • ไปที่การตั้งค่า > แอป > [ชื่อแอป] > สิทธิ์ > อุปกรณ์ใกล้เคียง > อนุญาต

ตอนนี้การเข้าถึงเครือข่ายภายในของแอปควรได้รับการคืนค่าแล้ว และสถานการณ์ทั้งหมดควรทำงานได้เหมือนก่อนที่จะเลือกใช้แอป ต่อไปนี้คือผลกระทบต่อการรับส่งข้อมูลเครือข่ายของแอป

Permission Outbound LAN Request Outbound/Inbound Internet Request Inbound LAN Request
Granted Works Works Works
Not Granted Fails Works Fails

ใช้คำสั่งต่อไปนี้เพื่อปิดการกำหนดค่า Appcompat

adb shell am compat disable RESTRICT_LOCAL_NETWORK <package_name>

ข้อผิดพลาด

หากคำขอเข้าถึงเครือข่ายภายในไม่สำเร็จเนื่องจากไม่มีสิทธิ์ ให้ทำดังนี้

  • การเชื่อมต่อ TCP มักจะส่งผลให้เกิดข้อผิดพลาดการหมดเวลา

  • ข้อผิดพลาด UDP และการปฏิเสธสิทธิ์ทั่วไปมักจะส่งผลให้เกิดรหัสข้อผิดพลาด EPERM

ข้อบกพร่อง

ส่งข้อบกพร่องและความคิดเห็นสำหรับกรณีต่อไปนี้

  • ความคลาดเคลื่อนในการเข้าถึง LAN (คุณคิดว่าการเข้าถึงบางอย่างไม่ควรพิจารณาเป็นการเข้าถึง "เครือข่ายภายใน")
  • ข้อบกพร่องที่ควรบล็อกการเข้าถึง LAN แต่ไม่บล็อก
  • ข้อบกพร่องที่ควรไม่บล็อกการเข้าถึง LAN แต่บล็อก

สิ่งต่อไปนี้ไม่ควรได้รับผลกระทบจากการเปลี่ยนแปลงนี้

  • การเข้าถึงอินเทอร์เน็ต
  • เครือข่ายมือถือ