Profil VPN iOS: passwordReference, bukan kata sandi
Referensi keychain adalah pegangan, bukan rahasianya. Mengirim byte menjelaskan galat -50, kegagalan saat reboot, dan jebakan rotasi pada profil VPN tersimpan.
Anda memasang profil, terowongan naik, dan semuanya tampak selesai. Lalu ponsel melakukan reboot, on-demand membangunkan koneksi tanpa aplikasi di latar depan, dan terowongan menolak start. Profilnya masih ada dan kata sandinya masih benar, itulah sebabnya kegagalan ini membuat orang mencari di tempat yang salah. Network Extension tidak bisa membaca rahasia Anda dari profil: ia membutuhkan referensi keychain yang bisa ia selesaikan sendiri.
Penelusuran di bawah mengikuti satu percobaan koneksi melalui penyerahan itu, dari kueri yang membangun referensi hingga reboot yang mengujinya.
Profil menyimpan pegangan, bukan rahasianya
NEVPNProtocol mengekspos passwordReference dan sharedSecretReference karena suatu alasan. Saat daemon memulai terowongan, ia mungkin tidak berjalan di dalam proses Anda, jadi ia tidak bisa memanggil kode Anda dan meminta kata sandi. Ia membaca referensi keychain yang persisten, menyelesaikannya dalam konteksnya sendiri, dan mengambil item itu sendiri.
Anda membangun referensi itu dengan memintanya kepada keychain, yang merupakan permintaan berbeda dari permintaan data:
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
]Serahkan objek yang dikembalikan ke protokol, bukan data item. Dalam praktiknya profil mencatat di mana rahasia itu tinggal, itulah sebabnya cadangan konfigurasi tidak diam-diam menggandakan kata sandi ke dalam plist.
Mengapa API menjawab -50
errSecParam berarti permintaan atau nilainya cacat untuk operasi itu, dan itulah galat yang paling sering terlihat ketika permintaan referensi dan data tertukar. Meminta data saat kode penerima mengharapkan referensi, menetapkan byte mentah ke passwordReference, atau membuat kueri dengan grup akses yang tidak bisa dipakai aplikasi, semuanya menghasilkannya.
Pustaka pembungkus mengundang hal ini. Helper yang mengembalikan byte tidak bisa ditukar dengan yang mengembalikan referensi, jadi perbaikannya biasanya kueri yang berbeda, bukan kata sandi yang berbeda.
Ketidakcocokan yang sama menjelaskan profil yang tersimpan tanpa keluhan lalu gagal terhubung: yang tersimpan adalah blob, bukan pegangan, dan daemon tidak punya apa pun untuk diselesaikan.
Tersimpan mulus, gagal saat koneksi
Penyimpanan melatih konteks aplikasi Anda. Koneksi melatih konteks daemon, dan keduanya tidak punya akses yang sama. Karena itu sebuah profil bisa lulus semua uji di simulator dan gagal pada start on-demand pertama.
Bentuk gejala reboot juga sama: berfungsi saat aplikasi terbuka dan mati ketika sistem memulai terowongan sendiri.
Uji jalur latar belakang dengan sengaja sebelum merilis. Picu koneksi on-demand dengan aplikasi tertutup, lalu baca konsol perangkat, bukan log aplikasi, karena kegagalannya dicatat oleh proses yang mencoba menyelesaikan referensi. Jika konsol menunjukkan daemon menolak item, referensinya baik dan masalahnya ada pada aksesibilitas item.
Aksesibilitas menentukan berhasil tidaknya reboot
Item harus bisa dibaca oleh proses sistem mana pun yang meluncurkan terowongan, dan itu audiens yang lebih luas daripada aplikasi Anda saat di latar depan. Batasan itu memilih atribut aksesibilitas untuk Anda. Item yang dilindungi hingga buka kunci pertama tersedia untuk start latar belakang setelah perangkat dibuka kunci sekali; item yang menuntut perangkat terbuka kunci sekarang tidak.
Memilih kelas yang lebih ketat memang menggoda dan justru itulah yang merusak profil on-demand di ponsel terkunci.
Setelah mengubah kelas, buat ulang item alih-alih menyunting atribut pada item yang ada, lalu simpan ulang protokol dengan referensi baru. Perubahan atribut pada item yang sudah ada tidak selalu menghasilkan perilaku yang disiratkan dokumentasi, dan item yang dibangun ulang menghilangkan keraguan.
Rotasi adalah tempat profil tersimpan membusuk
Mengubah kata sandi di keychain tidak otomatis mengubah apa yang ditunjuk profil tersimpan. Menghapus item lebih buruk: profil menyimpan referensi ke sesuatu yang sudah tidak ada, dan kegagalannya tampak seperti penolakan autentikasi.
Rotasikan dalam satu urutan. Perbarui item, kueri referensi persisten baru, simpan ulang protokol, lalu hubungkan dengan aplikasi tertutup untuk membuktikan daemon masih bisa menyelesaikannya. Simpan kata sandi pengguna dan rahasia bersama dalam item terpisah agar masing-masing berotasi sesuai jadwalnya, dan jangan pernah mencatat kamus kueri maupun referensinya sendiri. Pegangan itu bukan rahasia, tetapi peta menuju rahasia.