Keychain (Gantungan Kunci) — penyimpanan aman di iOS yang dirancang untuk menyimpan kata sandi, kunci kriptografi, sertifikat, dan catatan rahasia secara aman. Menurut Apple Security Documentation (2025), Keychain menggunakan enkripsi perangkat keras melalui Secure Enclave pada semua perangkat dengan chip A7 dan yang lebih baru. Memahami arsitektur iOS Keychain sangat penting bagi setiap pengembang untuk menyimpan token dan rahasia aplikasi dengan benar.
Utama
iOS Keychain — mekanisme penyimpanan data rahasia yang aman, tertanam di sistem operasi Apple. Tidak seperti UserDefaults atau file biasa, Keychain mengenkripsi semua elemen di tingkat perangkat keras dan memberikan kontrol akses yang terperinci berdasarkan kebijakan keamanan.
Keychain diperkenalkan di iOS 2.0 dan sejak itu mengalami perubahan signifikan: di iOS 7 ditambahkan dukungan untuk kunci perangkat keras melalui Secure Enclave, di iOS 9 — pembagian Keychain antar aplikasi melalui Access Groups, di iOS 13 — dukungan untuk pengikatan biometrik melalui LAContext. Menurut Apple WWDC Session (2024), lebih dari 90% aplikasi iOS di 100 besar App Store menggunakan Keychain untuk menyimpan token otentikasi.
Secara arsitektural, Keychain adalah basis data SQLite terenkripsi yang terletak di luar sandbox aplikasi. Setiap elemen (SecItem) dienkripsi dengan kunci terpisah, yang pada gilirannya dilindungi oleh kunci perangkat keras Secure Enclave. Layanan sistem Securityd mengelola akses ke Keychain berdasarkan hak aplikasi (entitlements) dan kelas perlindungan yang diminta.
Keuntungan penting Keychain dibandingkan metode penyimpanan lainnya: data secara otomatis dienkripsi dan didekripsi oleh sistem operasi. Pengembang tidak perlu mengimplementasikan kriptografi secara manual — cukup panggil SecItemAdd dengan parameter yang benar. iOS menjamin bahwa data dari Keychain tidak dapat dibaca oleh aplikasi lain (dengan konfigurasi Access Groups yang benar).
Arsitektur Keychain mencakup beberapa tingkat: fisik (Secure Enclave), sistem (Security.framework), aplikasi (API SecItem*) dan logis (Access Groups, Protection Classes). Memahami setiap tingkat membantu merancang penyimpanan rahasia dengan benar.
API utama untuk bekerja dengan Keychain adalah fungsi Security framework: SecItemAdd untuk menambah, SecItemCopyMatching untuk membaca, SecItemUpdate untuk memperbarui dan SecItemDelete untuk menghapus. Setiap fungsi menerima kamus query yang menjelaskan atribut elemen yang dicari atau disimpan.
Atribut kunci query: kSecClass — jenis elemen (kSecClassGenericPassword, kSecClassKey, kSecClassCertificate), kSecAttrAccount — pengidentifikasi unik dalam kelas, kSecValueData — data yang disimpan (Data), kSecAttrAccessible — kelas perlindungan. SecItemCopyMatching dengan flag kSecReturnData mengembalikan data elemen, dengan kSecMatchLimit — jumlah hasil.
Penting: semua fungsi mengembalikan status OSStatus. Operasi berhasil mengembalikan errSecSuccess (0). Kesalahan: errSecItemNotFound (-25300) — elemen tidak ditemukan, errSecDuplicateItem (-25299) — elemen sudah ada, errSecAuthFailed (-25293) — otentikasi biometrik gagal. Pengembang harus menangani setiap status dengan benar.
Protection Class — atribut kSecAttrAccessible, yang menentukan kapan data di Keychain tersedia untuk dibaca. iOS mendukung enam kelas perlindungan dengan tingkat ketersediaan dan keamanan yang berbeda.
Kelas yang direkomendasikan untuk sebagian besar skenario adalah kSecAttrAccessibleWhenUnlockedThisDeviceOnly: data hanya tersedia saat perangkat tidak terkunci dan tidak disalin ke iCloud Backup. Untuk data yang harus tersedia setelah restart (tetapi hanya setelah pembukaan pertama), gunakan kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly. Untuk data kritis yang memerlukan otentikasi biometrik setiap kali diakses, gabungkan kSecAttrAccessibleWhenUnlockedThisDeviceOnly dengan ACL yang memerlukan biometri.
Kelas tanpa akhiran ThisDeviceOnly (kSecAttrAccessibleWhenUnlocked, kSecAttrAccessibleAfterFirstUnlock) mengizinkan penyalinan ke iCloud Backup. Ini nyaman bagi pengguna, tetapi mengurangi keamanan — data dapat dipulihkan dari cadangan. Untuk token otentikasi, selalu gunakan ThisDeviceOnly.
Access Control List (ACL) — mekanisme yang membatasi operasi pada elemen Keychain berdasarkan otentikasi pengguna. ACL diatur melalui SecAccessControlCreateWithFlags dan diteruskan ke atribut kSecAttrAccessControl saat menyimpan elemen.
Flag yang didukung: kSecAccessControlUserPresence — otentikasi apa pun (Face ID, Touch ID atau kode sandi), kSecAccessControlBiometryCurrentSet — hanya biometri (sidik jari atau wajah yang terdaftar saat ini), kSecAccessControlDevicePasscode — hanya kode sandi. ACL diterapkan pada setiap operasi: membaca, memperbarui dan menghapus elemen juga memerlukan otentikasi.
Di iOS 15+ muncul flag kSecAccessControlWatch — untuk Apple Watch, yang memungkinkan otentikasi melalui jam tangan yang dipasangkan. ACL dapat digabungkan: misalnya, kSecAccessControlUserPresence atau kSecAccessControlBiometryAny dengan kode sandi opsional (orientasi .or).
iOS Keychain mendukung empat kelas elemen utama (kSecClass), masing-masing ditujukan untuk tipe datanya sendiri. Pemilihan kelas yang tepat menyederhanakan organisasi dan pencarian elemen.
kSecClassGenericPassword — kata sandi umum: kelas yang paling sering digunakan. Menyimpan data biner arbitrer (Data) dengan kunci unik (kSecAttrAccount). Cocok untuk token, kunci API, kode PIN. Tidak memerlukan entitlements tambahan untuk digunakan.
kSecClassInternetPassword — kata sandi internet: menyimpan data yang terkait dengan sumber daya jaringan. Atribut tambahan: kSecAttrServer (domain server), kSecAttrProtocol (https, ftp), kSecAttrPort, kSecAttrAuthenticationType. iOS dapat mengisi kata sandi tersebut secara otomatis melalui AutoFill.
kSecClassKey — kunci kriptografi: untuk menyimpan kunci enkripsi (AES, RSA, EC). Kunci disimpan sebagai SecKeyRef, bukan sebagai Data. kSecClassCertificate — sertifikat X.509 untuk menyimpan dan memverifikasi sertifikat digital. Kedua kelas memerlukan pemahaman operasi kriptografi dan konfigurasi atribut yang benar.
Dalam praktiknya, 95% kasus penggunaan Keychain di aplikasi seluler dicakup oleh kSecClassGenericPassword untuk menyimpan token otentikasi dan kSecClassKey untuk menyimpan kunci enkripsi pribadi. kSecClassCertificate jarang digunakan — biasanya di aplikasi perusahaan dengan PKI sendiri.
Mari kita lihat contoh praktis bekerja dengan Keychain di Swift menggunakan Security framework. Setiap contoh mencakup penanganan kesalahan dan konfigurasi Protection Class yang benar.
Contoh dasar menyimpan token otentikasi di Keychain dengan perlindungan WhenUnlockedThisDeviceOnly. Kunci (kSecAttrAccount) adalah pengidentifikasi layanan, data (kSecValueData) adalah token dalam format Data.
import Security
enum KeychainError: Error {
case unexpectedStatus(OSStatus)
}
func saveToken(token: String, service: String) throws {
let data = Data(token.utf8)
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: service,
kSecAttrAccount as String: "auth_token",
kSecValueData as String: data,
kSecAttrAccessible as String:
kSecAttrAccessibleWhenUnlockedThisDeviceOnly
]
SecItemDelete(query as CFDictionary)
let status = SecItemAdd(query as CFDictionary, nil)
guard status == errSecSuccess else {
throw KeychainError.unexpectedStatus(status)
}
}
func readToken(service: String) throws -> String {
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: service,
kSecAttrAccount as String: "auth_token",
kSecReturnData as String: true,
kSecMatchLimit as String: kSecMatchLimitOne
]
var result: AnyObject?
let status = SecItemCopyMatching(
query as CFDictionary, &result
)
guard status == errSecSuccess,
let data = result as? Data else {
throw KeychainError.unexpectedStatus(status)
}
return String(decoding: data, as: UTF8.self)
}
Contoh menunjukkan penggunaan SecAccessControlCreateWithFlags untuk mengikat kunci ke biometri. Setiap akses ke elemen akan memerlukan Face ID atau Touch ID.
import LocalAuthentication
func saveWithBiometry(data: Data, key: String) throws {
let accessControl = SecAccessControlCreateWithFlags(
nil,
kSecAttrAccessibleWhenUnlockedThisDeviceOnly,
.biometryCurrentSet,
nil
)
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrAccount as String: key,
kSecValueData as String: data,
kSecAttrAccessControl as String: accessControl as Any
]
SecItemDelete(query as CFDictionary)
let status = SecItemAdd(query as CFDictionary, nil)
guard status == errSecSuccess else {
throw KeychainError.unexpectedStatus(status)
}
}
Contoh menunjukkan konfigurasi Access Group untuk akses bersama ke Keychain antar aplikasi dari pengembang yang sama. Memerlukan entitlement keychain-access-groups.
// Capabilities: Keychain Sharing diaktifkan
// App IDs: group.com.example.shared
func saveSharedToken(token: Data) {
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrAccount as String: "shared_token",
kSecValueData as String: token,
kSecAttrAccessGroup as String:
"group.com.example.shared",
kSecAttrAccessible as String:
kSecAttrAccessibleWhenUnlockedThisDeviceOnly
]
SecItemAdd(query as CFDictionary, nil)
}
Penggunaan iOS Keychain yang benar memerlukan kepatuhan terhadap beberapa aturan kunci yang mencegah kerentanan umum dan kehilangan data.
Gunakan ThisDeviceOnly untuk semua rahasia otentikasi: kSecAttrAccessibleWhenUnlockedThisDeviceOnly menjamin bahwa token tidak akan masuk ke iCloud Backup. Jika penyerang mendapatkan akses ke cadangan, data Keychain dengan flag ini tidak akan tersedia. Pengecualian adalah data yang harus tersedia di semua perangkat pengguna (misalnya, kunci enkripsi untuk layanan sendiri), yang menggunakan kSecAttrAccessibleWhenUnlocked dengan kSecAttrSynchronizable.
Jangan simpan kata sandi mentah — simpan hash atau token sesi. Apple Security Guide (2025) merekomendasikan untuk tidak pernah menyimpan kata sandi pengguna di Keychain dalam teks biasa. Sebagai gantinya, simpan refresh token yang diperoleh dari server setelah otentikasi berhasil melalui OAuth 2.0. Kata sandi hanya digunakan untuk mendapatkan token dan segera dihapus dari memori.
Tangani kesalahan Keychain dengan benar: setiap operasi dengan Keychain mengembalikan OSStatus yang harus diperiksa. Perhatian khusus — errSecItemNotFound (token kedaluwarsa atau dihapus) dan errSecAuthFailed (biometri gagal). Dalam kasus pertama, aplikasi harus meminta otentikasi baru, dalam kasus kedua — tunjukkan metode alternatif kepada pengguna (kode sandi). Jangan pernah mengabaikan status errSecItemNotFound — ini akan menyebabkan aplikasi crash saat mencoba membaca nil.
Uji Keychain pada perangkat nyata: simulator tidak memiliki Secure Enclave dan tidak mendukung ACL biometrik. Selalu periksa skenario: peluncuran pertama, pemulihan dari cadangan, perubahan kata sandi perangkat, penghapusan dan instalasi ulang aplikasi. Pada perangkat nyata, Keychain dipertahankan setelah penghapusan aplikasi, tetapi hanya jika flag kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly tidak digunakan — flag ini akan dihapus saat kode sandi dihilangkan.
Minimalkan jumlah operasi dengan Keychain: setiap operasi baca atau tulis adalah panggilan ke layanan sistem Securityd yang dapat memblokir thread. Cache token yang dibaca di memori selama sesi dan akses Keychain lagi hanya saat restart aplikasi atau kesalahan otentikasi (401 dari server). iOS secara otomatis mengunci Keychain saat perangkat dikunci, oleh karena itu rencanakan pembacaan melalui LAContext dengan permintaan biometri.
Pertanyaan yang Sering Diajukan
Ya, gunakan kelas perlindungan kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly atau kSecAttrAccessibleAfterFirstUnlock. Data akan tersedia setelah pembukaan pertama perangkat setelah restart. Untuk akses otomatis saat aplikasi dimulai (tanpa menunggu pembukaan), gunakan kSecAttrAccessibleAlways, tetapi ini mengurangi keamanan.
Panggil SecItemDelete dengan query yang berisi kSecClass untuk setiap tipe data. Untuk pembersihan lengkap semua elemen aplikasi: SecItemDelete([kSecClass as String: kSecClassGenericPassword] as CFDictionary). Ulangi untuk kSecClassKey, kSecClassCertificate dan kSecClassInternetPassword.
kSecAttrAccessible menentukan kapan data tersedia (saat dibuka, setelah pembukaan pertama, dll.). kSecAttrAccessControl menentukan siapa yang dapat mengakses (biometri, kode sandi, otentikasi apa pun). Mereka digabungkan: pertama Protection Class, kemudian ACL. Misalnya, data hanya tersedia saat dibuka DAN hanya setelah Face ID.
Penyebab: elemen tidak pernah disimpan, elemen dihapus saat kode sandi dihilangkan (jika kSecAttrAccessibleWhenPasscodeSet digunakan), aplikasi diinstal ulang (Keychain dipertahankan tetapi tidak dipulihkan dari cadangan di perangkat baru), Access Group atau pengidentifikasi tim pengembang berubah. Periksa kSecAttrService dan kSecAttrAccount.
Gunakan LAContext dari LocalAuthentication: panggil context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: nil). Jika mengembalikan true — perangkat mendukung Touch ID atau Face ID. Untuk ACL Keychain, gunakan flag biometryCurrentSet (hanya data biometrik saat ini) atau biometryAny (data yang terdaftar sebelumnya).
Kesimpulan
Kami akan mengembangkan aplikasi seluler turnkey
IT Sectr membuat aplikasi iOS dan Android untuk startup dan bisnis sejak 2017. Kami akan memberi saran dan mengusulkan solusi terbaik.
Baca juga