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

การจับมือเปิดเผยมากกว่าหมายเลข

ตัวรับฟัง VPN แบบเนทีฟบน TCP 443 พูดโปรโตคอลของตัวเองตั้งแต่แพ็กเก็ตแรก ClientHello มีฟิลด์เวอร์ชัน ค่าสุ่ม และรายการส่วนขยาย และอุปกรณ์ที่อ่านไม่กี่ร้อยไบต์สามารถเห็นความต่างได้โดยไม่ต้องถอดรหัสอะไรเลย หมายเลขพอร์ตนั้นถูกทำให้พอใจได้ง่าย และรูปร่างของโปรโตคอลคือสิ่งที่ตัวกรองตรวจจริง ๆ กฎมักถูกเขียนแยกตามโปรโตคอลด้วย ดังนั้นนโยบายที่ตรวจ TLS จึงไม่บอกอะไรเกี่ยวกับ UDP

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

การห่อกระแสสร้างจุดล้มเหลวสองจุด

ตัวห่อ TLS อย่าง stunnel คืนรูปร่างที่คาดไว้: ไคลเอนต์เชื่อมต่อไปยังตัวรับฟังในเครื่อง ตัวห่อเปิดเซสชัน TLS จริงไปยังเซิร์ฟเวอร์บน 443 และตัวห่อที่สองบนเซิร์ฟเวอร์ส่งไบต์ที่ถอดรหัสแล้วไปยังเดมอน VPN เซสชันภายนอกตอนนี้ดูเหมือนการเชื่อมต่อ HTTPS อื่น ๆ เดมอน VPN บนเซิร์ฟเวอร์ควรรับฟังบน loopback เท่านั้น เพราะไม่มีอะไรนอกตัวห่อที่ต้องเข้าถึงมัน

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

เส้นทางไปยังตัวห่อคือกับดัก

เมื่ออุโมงค์ขึ้น เส้นทางเริ่มต้นชี้เข้าไปข้างใน และเซสชัน TLS ภายนอกต้องมีเส้นทางที่ไม่เข้าไปในอุโมงค์ที่มันหอบหิ้วอยู่ ไคลเอนต์ VPN ทั่วไปปกป้องที่อยู่ที่มันเรียก ส่วนไคลเอนต์ที่ถูกห่อเรียก loopback ของตัวเอง ที่อยู่ปลายทางของตัวห่อจึงมองไม่เห็นสำหรับการปกป้องนั้น

sudo ip route add 198.51.100.20 via 192.168.0.1
sudo openvpn --config client.ovpn
sudo ip route del 198.51.100.20

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

บน Android สิ่งที่เทียบเท่ากับข้อยกเว้นนั้นคือการตั้งค่าต่อแอป: ยกเว้นแอปตัวห่อออกจากอุโมงค์เพื่อให้ทราฟฟิกของมันเองออกผ่านการเชื่อมต่อมือถือ ถ้าไม่ยกเว้น ตัวห่อจะถูกส่งเข้าไปในอุโมงค์ที่มันพยายามสร้าง และลูปการเชื่อมต่อใหม่จะดูเหมือนปัญหาเซิร์ฟเวอร์

อ่านเวลาก่อนจะเปลี่ยนอะไร

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

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

จดพฤติกรรมที่สังเกตได้: เซสชันอยู่นานเท่าใด ซ็อกเก็ตเปิดหรือไม่ ตัวห่อบันทึกการจับมือหรือไม่ แต่ละอย่างทำให้การทดสอบถัดไปแคบลง

ทดสอบทีละตัวแปร

ตรวจ UDP ก่อน เพราะบางเครือข่ายทิ้งมันทั้งหมด และความล้มเหลวของ UDP ไม่บอกอะไรเกี่ยวกับ 443 จากนั้นลอง TCP 443 โดยไม่มีตัวห่อ แล้วจึงลองตัวห่อบน 443 อ่านบันทึกของไคลเอนต์ในแต่ละขั้นและหยุดทันทีที่พฤติกรรมเปลี่ยน

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

บทความที่เกี่ยวข้อง