โปรไฟล์ VPN บน iOS: passwordReference ไม่ใช่รหัสผ่าน
การอ้างอิงในคีย์เชนเป็นเพียงด้ามจับ ไม่ใช่ความลับ การส่งไบต์อธิบายข้อผิดพลาด -50 ความล้มเหลวเมื่อรีบูต และกับดักการหมุนเวียนในโปรไฟล์ VPN ที่บันทึกไว้
คุณติดตั้งโปรไฟล์ อุโมงค์เชื่อมต่อขึ้นมา และทุกอย่างดูเสร็จสมบูรณ์ จากนั้นโทรศัพท์รีบูต on-demand ปลุกการเชื่อมต่อโดยไม่มีแอปอยู่เบื้องหน้า และอุโมงค์ก็ปฏิเสธที่จะเริ่ม โปรไฟล์ยังอยู่และรหัสผ่านยังถูกต้อง นั่นคือเหตุผลที่ความล้มเหลวนี้ทำให้คนไปค้นหาผิดที่ Network Extension อ่านความลับของคุณจากโปรไฟล์ไม่ได้: มันต้องการการอ้างอิงในคีย์เชนที่มันแก้ได้เอง
คำอธิบายด้านล่างติดตามความพยายามเชื่อมต่อหนึ่งครั้งผ่านการส่งต่อนั้น ตั้งแต่คำสั่งที่สร้างการอ้างอิงไปจนถึงการรีบูตที่ทดสอบมัน
โปรไฟล์เก็บด้ามจับ ไม่ใช่ความลับ
NEVPNProtocol เปิดเผย passwordReference และ sharedSecretReference ด้วยเหตุผล เมื่อดีมอนเริ่มอุโมงค์ มันอาจไม่ได้ทำงานอยู่ในโปรเซสของคุณ จึงเรียกโค้ดของคุณเพื่อขอรหัสผ่านไม่ได้ มันอ่านการอ้างอิงถาวรในคีย์เชน แก้ในบริบทของตัวเอง และดึงรายการนั้นเอง
คุณสร้างการอ้างอิงนั้นโดยถามคีย์เชน ซึ่งเป็นคำขอที่ต่างจากคำขอข้อมูล:
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: "vpn-credentials",
kSecAttrAccount as String: "user",
kSecReturnPersistentRef as String: true,
kSecMatchLimit as String: kSecMatchLimitOne
]ส่งออบเจ็กต์ที่ได้คืนให้โปรโตคอล ไม่ใช่ข้อมูลของรายการ ในทางปฏิบัติ โปรไฟล์บันทึกว่าความลับอยู่ที่ไหน นั่นจึงเป็นเหตุผลที่สำรองข้อมูลการกำหนดค่าไม่คัดลอกรหัสผ่านเงียบ ๆ ลงใน plist
ทำไม API ตอบ -50
errSecParam หมายความว่าคำขอหรือค่าผิดรูปแบบสำหรับการดำเนินการนั้น และเป็นข้อผิดพลาดที่เห็นบ่อยที่สุดเมื่อคำขออ้างอิงและคำขอข้อมูลปนกัน การขอข้อมูลในขณะที่โค้ดผู้รับคาดหวังการอ้างอิง การกำหนดไบต์ดิบให้ passwordReference หรือการสอบถามด้วยกลุ่มการเข้าถึงที่แอปใช้ไม่ได้ ล้วนสร้างมันขึ้นมา
ไลบรารีห่อหุ้มชักชวนให้ทำเช่นนี้ ตัวช่วยที่คืนไบต์ใช้แทนกันไม่ได้กับตัวที่คืนการอ้างอิง การซ่อมจึงมักเป็นคำสั่งอื่น ไม่ใช่รหัสผ่านอื่น
ความไม่ตรงกันเดียวกันนี้อธิบายโปรไฟล์ที่บันทึกได้โดยไม่มีปัญหาแล้วเชื่อมต่อไม่ได้: สิ่งที่เก็บไว้คือก้อนข้อมูล ไม่ใช่ด้ามจับ และดีมอนไม่มีอะไรให้แก้
บันทึกได้ดี แต่ล้มเหลวตอนเชื่อมต่อ
การบันทึกใช้บริบทของแอปคุณ การเชื่อมต่อใช้บริบทของดีมอน และทั้งสองไม่ได้มีสิทธิ์เข้าถึงเท่ากัน โปรไฟล์จึงผ่านทุกการทดสอบในซิมูเลเตอร์และล้มเหลวในการเริ่ม on-demand ครั้งแรกได้
อาการเมื่อรีบูตก็มีรูปร่างแบบเดียวกัน: ทำงานได้ตราบใดที่แอปเปิดอยู่ และตายเมื่อระบบเริ่มอุโมงค์เอง
ทดสอบเส้นทางเบื้องหลังอย่างตั้งใจก่อนปล่อย ทริกเกอร์การเชื่อมต่อ on-demand ขณะแอปปิดอยู่ แล้วอ่านคอนโซลของอุปกรณ์ไม่ใช่บันทึกของแอป เพราะความล้มเหลวถูกบันทึกโดยโปรเซสที่พยายามแก้การอ้างอิง ถ้าคอนโซลแสดงว่าดีมอนปฏิเสธรายการ การอ้างอิงก็ดีและปัญหาคือการเข้าถึงรายการ
การเข้าถึงเป็นตัวตัดสินว่ารีบูตจะได้ผลหรือไม่
รายการต้องอ่านได้โดยโปรเซสระบบใดก็ตามที่เริ่มอุโมงค์ และนั่นคือผู้ชมที่กว้างกว่าแอปของคุณขณะอยู่เบื้องหน้า ข้อจำกัดนั้นเลือกแอตทริบิวต์การเข้าถึงให้คุณ รายการที่ป้องกันจนถึงการปลดล็อกครั้งแรกพร้อมใช้สำหรับการเริ่มเบื้องหลังหลังจากอุปกรณ์ถูกปลดล็อกหนึ่งครั้ง ส่วนรายการที่ต้องการให้อุปกรณ์ปลดล็อกอยู่ตอนนี้ไม่พร้อม
การเลือกคลาสที่เข้มงวดกว่าช่างน่าดึงดูด และนั่นคือสิ่งที่ทำให้โปรไฟล์ on-demand พังบนโทรศัพท์ที่ล็อกอยู่
หลังจากเปลี่ยนคลาส ให้สร้างรายการใหม่แทนการแก้แอตทริบิวต์ของรายการเดิม แล้วบันทึกโปรโตคอลอีกครั้งด้วยการอ้างอิงใหม่ การเปลี่ยนแอตทริบิวต์บนรายการเดิมไม่ได้ให้พฤติกรรมที่เอกสารสื่อเสมอไป และรายการที่สร้างใหม่จะขจัดข้อสงสัย
การหมุนเวียนคือที่ที่โปรไฟล์ที่บันทึกไว้เน่า
การเปลี่ยนรหัสผ่านในคีย์เชนไม่ได้เปลี่ยนสิ่งที่โปรไฟล์ที่บันทึกไว้ชี้ไปโดยอัตโนมัติ การลบรายการแย่กว่า: โปรไฟล์ยังคงอ้างอิงถึงสิ่งที่ไม่มีอยู่แล้ว และความล้มเหลวดูเหมือนการปฏิเสธการพิสูจน์ตัวตน
หมุนเวียนตามลำดับเดียว อัปเดตรายการ สอบถามการอ้างอิงถาวรใหม่ บันทึกโปรโตคอลอีกครั้ง แล้วเชื่อมต่อขณะแอปปิดอยู่เพื่อพิสูจน์ว่าดีมอนยังแก้ได้ เก็บรหัสผ่านผู้ใช้และความลับร่วมไว้ในรายการแยกกันเพื่อให้แต่ละรายการหมุนตามกำหนดของตัวเอง และอย่าบันทึกพจนานุกรมคำสั่งหรือการอ้างอิงนั้นเองลงล็อกเลย ด้ามจับไม่ใช่ความลับ แต่มันคือแผนที่ไปสู่ความลับ