ملف تعريف 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 على هاتف مقفل.
بعد تغيير الفئة، أعد إنشاء العنصر بدل تعديل السمات على العنصر القائم، ثم أعد حفظ البروتوكول بمرجع جديد. تغييرات السمات على عنصر قائم لا تنتج دائمًا السلوك الذي توحي به الوثائق، والعنصر المُعاد بناؤه يزيل الشك.
التدوير هو حيث تتعفّن الملفات المحفوظة
تغيير كلمة المرور في سلسلة المفاتيح لا يغيّر تلقائيًا ما يشير إليه الملف المحفوظ. حذف العنصر أسوأ: يبقي الملف مرجعًا إلى شيء لم يعد موجودًا، ويبدو الفشل كرفض مصادقة.
دوّر بترتيب واحد. حدّث العنصر، ثم استعلم عن مرجع دائم جديد، ثم أعد حفظ البروتوكول، ثم اتصل والتطبيق مغلق لتثبت أن الخادم الخفي ما زال قادرًا على حلّه. أبقِ كلمة مرور المستخدم والسر المشترك في عنصرين منفصلين ليدور كل منهما وفق جدوله، ولا تسجّل أبدًا قاموس الاستعلام ولا المرجع نفسه. المقبض ليس سرًا، لكنه خريطة إليه.