VPN บน Android โดยไม่ใช้ root: ใครเป็นเจ้าของความยินยอม เส้นทาง และการบล็อก
ความยินยอม อินเทอร์เฟซ TUN และนโยบายการบล็อกของระบบเป็นสิทธิ์สามอย่างที่แตกต่างกัน ระบุว่าองค์ประกอบใดเป็นเจ้าของแต่ละอย่างก่อนตรวจสอบแอป VPN สำหรับ Android
root ไม่ใช่สิ่งที่ทำให้แอป VPN บน Android ขนส่งทราฟฟิก บล็อกการรั่วไหล หรืออยู่รอดหลังรีบูต ผู้คนสรุปทั้งหมดนี้ว่า „แอปมีความยินยอม VPN“ ซึ่งซ่อนกลไกแยกกันสามอย่าง: ความยินยอมที่ผู้ใช้ให้ อินเทอร์เฟซแพ็กเก็ตที่ระบบสร้าง และนโยบายการบล็อกของแพลตฟอร์มที่แอปไม่ได้เป็นผู้กำหนด การตรวจสอบการออกแบบ VPN บน Android หมายถึงการถามว่าข้อกล่าวอ้างหนึ่งพึ่งพิงกลไกใดในสามอย่างนี้จริง ๆ เพราะแต่ละอย่างมีเจ้าของและรูปแบบความล้มเหลวที่ต่างกัน
ความยินยอมมาผ่านกิจกรรมของระบบ
VpnService.prepare() ไม่ได้ให้อะไรเลย มันคืน intent ไปยัง กิจกรรมความยินยอมของระบบ เมื่อยังไม่มีความยินยอม และแอปจะเปิดกล่องโต้ตอบนั้นเพื่อให้ผู้ใช้อนุมัติบริการ การเริ่มโปรเซสของแอปเอง การเพิ่มสิทธิ์ใน manifest หรือการแสดงหน้าจอ „เปิดใช้งาน VPN“ ที่กำหนดเองไม่ได้สร้างความยินยอม
ความยินยอมยังมีขอบเขตด้วย มันเป็นของแพ็กเกจในโปรไฟล์ผู้ใช้ ดังนั้นสำเนาส่วนตัวและสำเนางานจึงเป็นการตัดสินใจแยกกัน และเจ้าของอุปกรณ์สามารถเตรียมโปรไฟล์ที่จัดการได้ต่างจากโปรไฟล์ส่วนตัว หากกล่องโต้ตอบไม่เคยปรากฏและ prepare() คืนค่า null แสดงว่ามีความยินยอมสำหรับแพ็กเกจนั้นในโปรไฟล์นั้นอยู่แล้ว นั่นไม่ใช่หลักฐานว่าแอปน่าเชื่อถือ เพียงแต่สิทธิ์มีอยู่
อินเทอร์เฟซคือคำขอที่ระบบตอบสนอง
หลังความยินยอม แอปจะอธิบายสิ่งที่ต้องการด้วย VpnService.Builder: ที่อยู่ เส้นทาง เซิร์ฟเวอร์ DNS, MTU และเมื่อรองรับ แอปที่จะรวมหรือยกเว้น establish() ขอให้ระบบสร้างอินเทอร์เฟซอุโมงค์และส่งทราฟฟิกที่ตรงกันเข้าไป ระบบเป็นเจ้าของการตัดสินใจเส้นทาง แอปได้รับตัวอธิบายไฟล์แล้วจึงต้องทำอะไรที่เป็นประโยชน์กับแพ็กเก็ต
| What you observe | Who actually owns it |
|---|---|
| VPN consent dialog | The system, triggered by prepare() |
| Routes, DNS and app lists | The app requests them; the system applies them |
| One active VPN per profile | The platform; a new service replaces the old one |
| Always-on and block-without-VPN | Device policy enforced by the platform |
ตารางนั้นคือสถาปัตยกรรมในที่เดียว แอปมีส่วนร่วมในการจัดการแพ็กเก็ต แต่ไม่ได้เป็นเจ้าของอินเทอร์เฟซ ตารางเส้นทาง หรือจำนวนบริการที่อนุญาตให้ทำงาน
ซ็อกเก็ตของอุโมงค์ต้องหลบออกจากอุโมงค์ของตัวเอง
การเชื่อมต่อที่ขนส่งทราฟฟิกที่เข้ารหัสนั้นเองก็เป็นซ็อกเก็ต หากมันถูกส่งกลับเข้าไปในอินเทอร์เฟซที่แอปเพิ่งสร้างขึ้น อุโมงค์จะขึ้นกับอุโมงค์และหยุดชะงัก VpnService.protect() ผูกซ็อกเก็ตนั้นกับเครือข่ายพื้นฐานเพื่อให้ข้ามการดักจับ และนั่นคือเหตุผลที่ไคลเอนต์ที่ถูกต้องปกป้องซ็อกเก็ตภายนอกก่อนการจับมือครั้งแรก
adb shell dumpsys connectivity | grep -i -A5 vpn
adb shell settings get global always_on_vpn_app
adb shell settings get global always_on_vpn_lockdown
คำสั่งเหล่านี้แสดงเครือข่าย VPN ที่ติดตั้ง แพ็กเกจเปิดตลอดเวลา และว่าตั้งค่าการล็อกหรือไม่ เป็นการสังเกตแบบอ่านอย่างเดียว: หากค่าไม่ตรงกับที่การออกแบบอ้าง ข้อกล่าวอ้างนั้นเกี่ยวกับอินเทอร์เฟซของแอป ไม่ใช่สถานะของระบบ
การบล็อกอาจเป็นของแพลตฟอร์ม
Android จัดทำเอกสารนโยบายที่บล็อกการเชื่อมต่อที่ไม่ใช้ VPN การบังคับใช้ดังกล่าวเป็นสัญญาของแพลตฟอร์ม ไม่ใช่แอปที่พยายามเชื่อมต่อซ้ำเป็นวง สวิตช์อยู่ในตั้งค่า VPN ของอุปกรณ์ในชื่อ บล็อกการเชื่อมต่อเมื่อไม่มี VPN และบนอุปกรณ์ที่จัดการได้ เจ้าของสามารถเปิดให้ทั้งโปรไฟล์ ความแตกต่างนี้สำคัญเมื่อประเมินข้อกล่าวอ้างทางการตลาด: ไคลเอนต์อาจแสดงไอคอนกุญแจและเชื่อมต่อใหม่แบบเชิงรุกในขณะที่ทราฟฟิกตรงยังเป็นไปได้ หรือแอปที่ครอบคลุมอาจออฟไลน์เพราะระบบบังคับใช้การล็อก
ไอคอนกุญแจถูกวาดโดยแอป จึงพิสูจน์ได้เพียงว่าแอปเชื่อว่าตนเชื่อมต่ออยู่ หากแอปอื่นสูญเสียการเข้าถึงเครือข่าย แพลตฟอร์มเป็นผู้ตัดสิน ดังนั้นการตรวจสอบที่เป็นประโยชน์คือการดูแอปนั้นล้มเหลวขณะอุโมงค์ทำงาน
ป้าย „เปิดตลอดเวลา“ จากร้านแอปก็ไม่ได้แทนที่สัญญานั้น การเปิดตลอดเวลาและการล็อกเป็นการตั้งค่าอุปกรณ์ ซึ่งมักถูกใช้โดยเจ้าของ และพฤติกรรมของมันต่อแอปที่ยกเว้นถูกกำหนดโดยแพลตฟอร์ม อ่านการตั้งค่า ไม่ใช่ป้าย
สี่คำถามสำหรับการทบทวนการออกแบบ
หนึ่ง ใครให้ความยินยอม: แพ็กเกจใด โปรไฟล์ใด และเป็นผู้ใช้หรือนโยบายอุปกรณ์ที่จัดการ สอง แอปขออะไร: เส้นทางใด ตระกูลที่อยู่ใด แอปใดถูกรวมหรือยกเว้น สาม เกิดอะไรขึ้นเมื่ออุโมงค์ไม่พร้อมใช้งาน: ระบบบล็อกหรือทราฟฟิกตกกลับไปยังเครือข่ายพื้นฐาน สี่ แอปทำอะไรกับแพ็กเก็ตที่ได้รับ
คำถามที่สี่คือคำถามที่โมเดลสิทธิ์ตอบไม่ได้ ความยินยอมและอินเทอร์เฟซ TUN พิสูจน์ว่าแอปสามารถรับทราฟฟิกได้ ไม่ได้พิสูจน์ว่ามันเข้ารหัส ตรวจสอบอีกฝ่าย หรือกู้คืนอย่างสะอาด นั่นคือคุณสมบัติของการนำไปใช้ และนั่นคือที่ที่การทบทวนอย่างซื่อสัตย์ใช้เวลา
คำขอ root ที่ไม่จำเป็นไม่ได้กลายเป็นชอบธรรมเพียงเพราะเรียกผลลัพธ์ว่าคิลสวิตช์ และกล่องโต้ตอบความยินยอมไม่ใช่การตรวจสอบความปลอดภัย แยกสิทธิ์ทั้งสามออกจากกัน แล้วทุกข้อกล่าวอ้างจะตรวจสอบได้