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

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

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

ผลกระทบ

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

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

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

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

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

การดำเนินการเครือข่ายระดับต่ำของแอป ต้องมีสิทธิ์เข้าถึงเครือข่ายภายใน
สร้างการเชื่อมต่อ TCP ขาออก ใช่
การยอมรับการเชื่อมต่อ TCP ขาเข้า ใช่
การส่ง Unicast, Multicast, Broadcast แบบ UDP ใช่
รับการรับส่งข้อมูลแบบ UDP ยูนิแคสต์ มัลติแคสต์ บรอดแคสต์ ใช่

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

ข้อยกเว้นสำหรับกฎข้างต้น

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

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

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

อัตราส่วน Android 16 Android 17
SDK เป้าหมาย 36 37 ขึ้นไป
สิทธิ์ ใช้ NEARBY_WIFI_DEVICES ชั่วคราว ACCESS_LOCAL_NETWORK
สิทธิ์เข้าถึงเริ่มต้น การเข้าถึงเครือข่ายภายในเปิดอยู่ ระบบจะบล็อกเครือข่าย LAN โดยค่าเริ่มต้นสำหรับแอปทั้งหมดที่อัปเดต 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
    }
})

เส้นทาง B: ขอสิทธิ์รันไทม์ (การเข้าถึงแบบกว้าง)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

สิทธิ์ คำขอ LAN ขาออก คำขออินเทอร์เน็ตขาออก/ขาเข้า คำขอ LAN ขาเข้า
ให้สิทธิ์ Works Works Works
ไม่ให้สิทธิ์ เรื่องหน้าแตก Works เรื่องหน้าแตก

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

adb shell am compat disable RESTRICT_LOCAL_NETWORK <package_name>

ข้อผิดพลาด

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

  • โดยปกติแล้ว การเชื่อมต่อ TCP จะทำให้เกิดข้อผิดพลาดหมดเวลา

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

ข้อบกพร่อง

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

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

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

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