บล็อกข้อความธรรมดาในแอป Android โดยไม่พึ่ง VPN
ข้อความธรรมดาในเพย์โหลดและข้อความธรรมดาบนเส้นทางเป็นปัญหาที่ต่างกัน แก้ปัญหาแรกในแอป และปัญหาที่สองด้วยอุโมงค์หรือนโยบายอุปกรณ์
มีสองสิ่งที่ต่างกันโดยสิ้นเชิงที่ถูกเรียกว่าการบล็อกข้อความธรรมดาบน Android อย่างหนึ่งคือนโยบายภายในแอปที่สั่งให้สแตกเครือข่ายของตัวเองปฏิเสธ HTTP ธรรมดา อีกอย่างคือการจัดวางระดับอุปกรณ์ที่พยายามปกป้องทุกอย่างบนโทรศัพท์พร้อมกัน โดยปกติด้วยการส่งทราฟฟิกผ่าน VPN ทั้งสองแก้ปัญหาต่างกัน และอย่างที่สองไม่สามารถแก้อย่างแรกได้ อุโมงค์ปกป้องช่วงระหว่างโทรศัพท์กับทางออก แต่แอปที่พูด HTTP ก็ยังพูด HTTP กับทุกสิ่งเลยทางออกนั้นไป
สองปัญหาภายใต้ชื่อเดียว
ปัญหาแรกคือเพย์โหลด แอปเขียนข้อมูลรับรองหรือโทเคนลงในคำขอที่ไม่ถูกเข้ารหัสตั้งแต่ต้นจนจบ ดังนั้นทุกฮอปที่มองเห็นก็อ่านได้ ปัญหาที่สองคือเส้นทาง แอปอาจถูกต้องสมบูรณ์ และคุณยังต้องการให้ผู้ให้บริการ Wi-Fi ในพื้นที่ไม่รู้อะไรเลยเกี่ยวกับที่ที่มันเชื่อมต่อ VPN จัดการอย่างที่สองเท่านั้น
ความแตกต่างนั้นกำหนดว่าใครเป็นเจ้าของการแก้ไข เพย์โหลดเป็นของผู้ที่ส่งมอบแอป เพราะมีเพียงโค้ดนั้นที่กำหนดว่าจะเรียก URL ใดและจะตรวจสอบใบรับรองหรือไม่ เส้นทางเป็นของอุปกรณ์หรือเครือข่าย เพราะเป็นเรื่องของว่าแพ็กเก็ตไปที่ใด ไม่ใช่มีอะไรอยู่ข้างใน
เส้นทางที่หนึ่ง: แอปที่คุณควบคุม
หากคุณส่งมอบแอป การแก้ไขคือการตัดสินใจเรื่องการรับส่งบวกนโยบายที่บังคับใช้ ชี้ทุกปลายทางไปที่ HTTPS คงการตรวจสอบชื่อโฮสต์และใบรับรองไว้ และลบทางถอยกลับไปใช้ HTTP ธรรมดาแทนที่จะปล่อยให้อยู่ห่างเพียงแฟล็กการกำหนดค่าเดียว การเปลี่ยนเส้นทางไม่ช่วยที่นี่ คำขอ HTTP ที่ได้รับ 301 ได้ส่งส่วนหัวและเนื้อหาแบบเปิดเผยไปแล้ว ดังนั้นข้อมูลรับรองต้องไม่เดินทางด้วยสมมติฐานว่าการเปลี่ยนเส้นทางจะปกป้องมัน
ตั้งแต่ Android 7.0 เป็นต้นมา Network Security Configuration เป็นตัวแสดงนโยบาย ไฟล์ด้านล่างเป็นเวอร์ชันที่มีประโยชน์เล็กที่สุด มันปฏิเสธข้อความธรรมดาทุกที่ เว้นแต่ข้อยกเว้นเฉพาะโดเมนจะบอกเป็นอย่างอื่น
<network-security-config>
<base-config cleartextTrafficPermitted="false" />
</network-security-config>อ้างอิงทรัพยากรนั้นจากแมนิเฟสต์ แล้วอ่านข้อยกเว้นที่มีอยู่แล้วก่อนส่งมอบ โดเมนดีบักเก่าหรือรายการ SDK ของผู้ให้บริการชำระเงินอาจอนุญาตข้อความธรรมดาอีกครั้งอย่างเงียบ ๆ สำหรับโฮสต์ที่คุณพยายามปกป้อง
รายละเอียดเวอร์ชันสองข้อที่ควรรู้ แอปที่กำหนดเป้าหมาย API 28 หรือใหม่กว่าปฏิเสธข้อความธรรมดาเป็นค่าเริ่มต้นอยู่แล้ว ดังนั้นแอปที่ยังพูด HTTP ธรรมดาจึงกำหนดเป้าหมายระดับ API เก่ากว่าหรือมีข้อยกเว้นที่ใดที่หนึ่ง และเมื่อมีคอนฟิกความปลอดภัยเครือข่าย แอตทริบิวต์แมนิเฟสต์เก่า android:usesCleartextTraffic จะไม่ตัดสินคำถามนั้นอีกต่อไป ซึ่งเป็นเหตุผลที่บางครั้งการเปลี่ยนแฟล็กนั้นดูเหมือนไม่ได้ทำอะไร
เส้นทางที่สอง: แอปที่คุณไม่ได้ควบคุม
สำหรับแอปของบุคคลที่สามที่ติดตั้งไว้ คุณไม่สามารถเขียนการกำหนดค่าความปลอดภัยใหม่ผ่านการตั้งค่าผู้ใช้ได้ ตัวเลือกที่เป็นจริงคือการควบคุมการเชื่อมต่อที่ปลอดภัยของผลิตภัณฑ์เอง ทางเลือกที่ได้รับการดูแลซึ่งใช้ TLS อยู่แล้ว หรือนโยบายอุปกรณ์ที่ได้รับการจัดการซึ่งจำกัดสิ่งที่อุปกรณ์ทำได้ สิ่งเหล่านี้คือพันธะที่ต่างกัน และมีเพียงอย่างที่สามเท่านั้นที่ขยายไปยังกองอุปกรณ์
กฎเครือข่ายเป็นตัวทดแทนที่อ่อนแอกว่าที่เห็น อนุญาตเฉพาะพอร์ต 443 ไม่ได้บังคับ TLS ที่ผ่านการพิสูจน์ตัวตน เพราะโปรโตคอลข้อความธรรมดาหลายตัวสามารถย้ายมาที่พอร์ตนั้นได้ และการบล็อกพอร์ต 80 ไม่ครอบคลุมข้อความธรรมดาบนพอร์ตอื่น โหมดเฉพาะ HTTPS ของเบราว์เซอร์ก็จำกัดอยู่ที่เบราว์เซอร์นั้น ไม่ใช่แอปอีเมลหรือแชทแยกต่างหากบนโทรศัพท์เครื่องเดียวกัน
การติดตั้งใบรับรองดักจับเพื่อให้ทราฟฟิกดูเหมือนถูกเข้ารหัสเป็นการเปลี่ยนความไว้วางใจ ไม่ใช่การแก้ไข มันแทนที่การพิสูจน์ตัวตนเซิร์ฟเวอร์ของแอปด้วยของคุณ และแอปที่ไม่ได้ตรวจสอบใบรับรองตั้งแต่แรกก็ไม่ได้ถูกแก้ไขด้วยวิธีนี้ คุณเพียงย้ายว่าคุณสามารถอ่านสตรีมได้
VPN ช่วยที่ไหนและไม่ช่วยที่ไหน
อุโมงค์เป็นเครื่องมือที่ถูกต้องเมื่อข้อกำหนดคือเครือข่ายท้องถิ่นไม่รู้อะไรเลยเกี่ยวกับการเชื่อมต่อ หรือแอปเข้าถึงบริการส่วนตัวที่เข้าถึงไม่ได้ด้วยวิธีอื่น มันเป็นเครื่องมือที่ผิดสำหรับทำให้ไคลเอนต์ HTTP พูด HTTPS เพราะคำขอออกจากอุโมงค์เหมือนเดิมทุกประการที่เข้ามา
Android เพิ่มข้อจำกัดในทางปฏิบัติ: แพลตฟอร์มรันบริการ VPN ได้ครั้งละหนึ่งเท่านั้น. แอปกรองในเครื่องที่ใช้ที่นั้นแข่งขันกับอุโมงค์ระยะไกลที่คุณต้องการจริง ๆ และการสลับระหว่างสองสิ่งเป็นการดำเนินการระดับอุปกรณ์ไม่ใช่ระดับแอป ที่เดียวนั้นเป็นเหตุผลดีที่จะเก็บนโยบายเพย์โหลดไว้ในแอปและเก็บอุโมงค์ไว้สำหรับเส้นทาง
กรณีเดียวที่ทั้งสองทับซ้อนกันคือเซิร์ฟเวอร์ส่วนตัวที่คุณดำเนินการเองด้วย ที่นั่นอุโมงค์ทำให้เส้นทางเป็นส่วนตัวได้แม้โปรโตคอลยังเป็นข้อความธรรมดา ซึ่งลดการเปิดเผยแต่ไม่ได้เปลี่ยนว่าเพย์โหลดคืออะไร มองสิ่งนั้นเป็นการลดความเสี่ยง ไม่ใช่การเข้ารหัสข้อมูล
สิ่งที่ต้องทดสอบก่อนจะเรียกว่าถูกบล็อก
เริ่มจากค่าเริ่มต้นที่ทำให้คนประหลาดใจ แอปที่กำหนดเป้าหมาย API 28 หรือใหม่กว่าควรปฏิเสธข้อความธรรมดาอยู่แล้ว ดังนั้นตรวจสอบระดับเป้าหมายก่อนเพิ่มการกำหนดค่าที่ซ้ำกับค่าเริ่มต้น จากนั้นทดสอบกรณีล้มเหลวโดยเจตนา คำขอไปยังโฮสต์ HTTP ธรรมดาต้องล้มเหลว ไม่ใช่สำเร็จอย่างเงียบ ๆ ผ่านทางถอยกลับ
adb shell dumpsys package com.example.app | grep -E 'targetSdk|versionName'
adb logcat | grep -i cleartextสำหรับกรณีสำเร็จ ยืนยันว่าการเรียก HTTPS ตรวจสอบห่วงโซ่ใบรับรองจริง และพร็อกซีที่มีใบรับรองที่ไม่น่าไว้วางใจถูกปฏิเสธไม่ใช่ถูกอดทน การจับมือที่สำเร็จกับใบรับรองใดก็ได้ไม่ได้พิสูจน์อะไรเกี่ยวกับความปลอดภัยของการรับส่ง
สำหรับแอปของบุคคลที่สาม จดขอบเขตที่คุณบังคับใช้ได้จริง ไม่ว่าจะเป็นนโยบายอุปกรณ์ที่ได้รับการจัดการ กฎเครือข่าย หรือไม่มีอะไรเลย และระบุไว้ในเกณฑ์การยอมรับ คู่มือการกำหนดค่าความปลอดภัยของ Android แสดงค่าเริ่มต้นของแพลตฟอร์มและคอมโพเนนต์ใดเคารพนโยบาย และนั่นคือส่วนที่กำหนดว่าการกำหนดค่าของคุณทำอะไรได้บ้าง