Keychain — یک مخزن امن اطلاعات احراز هویت در iOS، watchOS، macOS و tvOS است که رمزهای عبور، کلیدها و گواهیها را در سطح سختافزاری مدیریت میکند. برخلاف UserDefaults، دادهها در Keychain رمزگذاری شده و توسط sandbox برنامه ایزوله میشوند. طبق Apple Developer Documentation، Keychain از مکانیزمهای Secure Enclave و رمزگذاری سختافزاری AES-256 برای محافظت از اطلاعات محرمانه استفاده میکند.
نکات اصلی
Keychain — یک پایگاه داده امن از سیستم عامل اپل است که برای ذخیرهسازی امن رمزهای عبور، کلیدهای رمزنگاری، گواهیها و سایر دادههای محرمانه طراحی شده است. Keychain اولین بار در Mac OS 8.6 در سال 1999 ظاهر شد و در iOS از اولین نسخه SDK حضور دارد.
Keychain یک مشکل اساسی توسعه موبایل را حل میکند: ذخیرهسازی اسرار (توکنها، رمزهای عبور، کلیدهای رمزگذاری) در سیستم فایل محافظتنشده. برخلاف UserDefaults یا SQLite، دادهها در Keychain به صورت رمزگذاری شده ذخیره میشوند و هنگام نوشتن روی دیسک به طور خودکار رمزگذاری میشوند.
هر برنامه iOS در یک sandbox ایزوله کار میکند و فقط به keychain خود دسترسی دارد. با این حال، توسعهدهنده میتواند دسترسی مشترک به Keychain بین برنامههای یک توسعهدهنده را از طریق keychain access groups پیکربندی کند. کاربر iCloud Keychain همچنین دادهها را بین دستگاهها از طریق رمزگذاری end-to-end همگامسازی میکند.
طبق Apple Security White Paper (2025)، Keychain از رمزگذاری سختافزاری AES-256 با کلید متصل به شناسه یکتای دستگاه (UID) استفاده میکند که دادهها را هنگام استخراج از دستگاه غیرقابل دسترس میکند.
Keychain به عنوان یک سرویس لایهای عمل میکند: برنامه به Security framework مراجعه میکند که با دیمن securityd تعامل دارد و پایگاه داده رمزگذاری شده SQLite Keychain را مدیریت میکند. هر رکورد با یک کلید جداگانه رمزگذاری میشود و خود کلیدها توسط ماژول سختافزاری Secure Enclave در دستگاههای دارای تراشه A7 و جدیدتر محافظت میشوند.
Security framework یک رابط C برای کار با Keychain Services فراهم میکند. توابع اصلی: SecItemAdd (افزودن)، SecItemCopyMatching (جستجو)، SecItemUpdate (بهروزرسانی) و SecItemDelete (حذف). هر عملیات یک دیکشنری از ویژگیهای CFDictionaryRef را دریافت میکند که نوع درخواست را توصیف میکند.
دادهها بر اساس کلاسها طبقهبندی میشوند: kSecClassGenericPassword (رمز عبور دلخواه)، kSecClassInternetPassword (رمز عبور سرویس اینترنتی)، kSecClassCertificate (گواهی)، kSecClassKey (کلید رمزنگاری) و kSecClassIdentity (ترکیب کلید و گواهی).
هنگام ذخیره رمز عبور، برنامه یک دیکشنری با ویژگیها میسازد: سرویس، حساب، سطح دسترسی، برچسب. Security framework دادهها را به دیمن securityd ارسال میکند که رکورد را با کلید متصل به دستگاه رمزگذاری کرده و در Keychain SQLite ذخیره میکند. استخراج به طور مشابه انجام میشود: درخواست بر اساس ویژگیها، جستجو، رمزگشایی و بازگرداندن داده.
یک ویژگی مهم: هنگام حذف برنامه، iOS به طور خودکار Keychain را پاک میکند از رکوردهایی که توسط این برنامه ایجاد شدهاند (از iOS 10.3+). هنگام نصب مجدد برنامه، دادههای Keychain نصب قبلی غیرقابل دسترس هستند، مگر اینکه از iCloud Keychain استفاده شده باشد.
import Security
func savePassword(service: String, account: String, password: Data) {
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: service,
kSecAttrAccount as String: account,
kSecValueData as String: password,
kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlocked
]
SecItemAdd(query as CFDictionary, nil)
}
Keychain از پنج کلاس اصلی داده پشتیبانی میکند که هر کدام مجموعه ویژگیهای خاص خود و حوزه کاربرد دارند. انتخاب کلاس تعیین میکند که کدام کلیدهای جستجو در دسترس هستند و دادهها چگونه رمزگذاری میشوند.
کلاسهای kSecClassGenericPassword و kSecClassInternetPassword برای ذخیره رمزهای عبور متنی طراحی شدهاند. نسخه اینترنتی علاوه بر این دادههای سرور را ذخیره میکند: دامنه، پروتکل، پورت و مسیر احراز هویت. GenericPassword برای ذخیره هر رمز عبوری بدون اتصال به سرور استفاده میشود.
هنگام ذخیره رمز عبور اینترنتی میتوان kSecAttrServer (دامنه)، kSecAttrProtocol (HTTPS، FTP و غیره)، kSecAttrPort و kSecAttrPath را مشخص کرد. این امکان شناسایی دقیق رکورد را هنگام پر کردن خودکار از طریق AutoFill فراهم میکند.
کلاس kSecClassKey کلیدهای متقارن (AES) و نامتقارن (RSA, EC) را ذخیره میکند. کلاس kSecClassCertificate — گواهیهای X.509. کلاس kSecClassIdentity کلید خصوصی و گواهی مربوطه را در یک رکورد ترکیب میکند.
برای کلیدهای نامتقارن، Keychain از ویژگیها پشتیبانی میکند: kSecAttrKeyType (RSA, EC)، kSecAttrKeySizeInBits (2048, 256)، kSecAttrIsPermanent (آیا در Keychain ذخیره شود). برای گواهیها: kSecAttrLabel (نام قابل خواندن برای انسان)، kSecAttrSubject (DN مالک)، kSecAttrIssuer (DN صادرکننده).
| کلاس Keychain | هدف | نوع داده |
|---|---|---|
| kSecClassGenericPassword | رمز عبور برنامه | Data (NSString) |
| kSecClassInternetPassword | رمز عبور سرور | Data + ویژگیهای سرور |
| kSecClassCertificate | گواهی X.509 | SecCertificate |
| kSecClassKey | کلید رمزنگاری | SecKey |
| kSecClassIdentity | کلید + گواهی | SecIdentity |
رابط اصلی تعامل با Keychain در کد بومی iOS — توابع Security framework. برای Swift و Objective-C یک رابط C موجود است که در توابع راحت پیچیده شده است.
تابع SecItemAdd یک عنصر جدید به Keychain اضافه میکند. ورودی یک دیکشنری با کلاس، داده و ویژگیها را دریافت میکند. وضعیت errSecSuccess (0) یا کد خطا را برمیگرداند. تابع SecItemCopyMatching جستجو بر اساس ویژگیها را انجام میدهد و دادههای یافت شده را برمیگرداند.
برای جستجو از پرچم kSecReturnData استفاده میشود — اگر true باشد، تابع محتوای رکورد را برمیگرداند. پرچم kSecMatchLimit تعداد نتایج را تعیین میکند: kSecMatchLimitOne (یک) یا kSecMatchLimitAll (همه).
func readPassword(service: String, account: String) -> Data? {
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: service,
kSecAttrAccount as String: account,
kSecReturnData as String: true,
kSecMatchLimit as String: kSecMatchLimitOne
]
var item: CFTypeRef?
let status = SecItemCopyMatching(query as CFDictionary, &item)
guard status == errSecSuccess else { return nil }
return item as? Data
}
SecItemUpdate امکان تغییر ویژگیها یا دادههای رکورد موجود را فراهم میکند. SecItemDelete تمام رکوردهای مطابق با دیکشنری ارسال شده را حذف میکند. هنگام حذف، مهم است که ویژگیهای کافی مشخص شود تا به طور تصادفی رکوردهای دیگران در shared keychain حذف نشود.
func deletePassword(service: String, account: String) {
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: service,
kSecAttrAccount as String: account
]
SecItemDelete(query as CFDictionary)
}
هر رکورد Keychain دارای ویژگی kSecAttrAccessible است که تعیین میکند دادهها چه زمانی برای خواندن در دسترس هستند. این برای امنیت حیاتی است: سطح دسترسی اشتباه میتواند دادهها را آسیبپذیر یا برعکس، در لحظه مورد نیاز غیرقابل دسترس کند.
kSecAttrAccessibleWhenUnlocked — دادهها فقط زمانی در دسترس هستند که دستگاه باز باشد. kSecAttrAccessibleAfterFirstUnlock — پس از اولین باز کردن قفل پس از راهاندازی مجدد در دسترس هستند. kSecAttrAccessibleAlways — همیشه در دسترس هستند (توصیه نمیشود). پسوند ThisDeviceOnly انتقال داده از طریق پشتیبانگیری را ممنوع میکند.
در دستگاههای دارای Secure Enclave، کلید رمزگذاری Keychain میتواند علاوه بر این با بیومتریک محافظت شود: kSecAccessControlBiometryCurrentSet یا kSecAccessControlUserPresence. این کار برای هر عملیات خواندن نیاز به Face ID یا Touch ID اضافه میکند.
iCloud Keychain رکوردها را بین دستگاههای اپل از طریق رمزگذاری end-to-end همگامسازی میکند. اپل به دادههای رمزگشایی شده دسترسی ندارد. برای فعالسازی همگامسازی، ویژگی kSecAttrSynchronizable را با مقدار kCFBooleanTrue اضافه کنید.
مهم: رکوردهای همگامسازی شده نمیتوانند ویژگی ThisDeviceOnly را داشته باشند، زیرا باید در دستگاههای دیگر در دسترس باشند. هنگام از دست دادن همه دستگاهها، iCloud Keychain از طریق کد بازیابی یا کلید پشتیبان iCloud بازیابی میشود.
برای توکنهای احراز هویت از kSecAttrAccessibleWhenUnlockedThisDeviceOnly استفاده کنید — دادهها فقط در دستگاه باز در دسترس هستند و به پشتیبان کپی نمیشوند. برای گواهیهایی که باید برای وظایف پسزمینه در دسترس باشند، از kSecAttrAccessibleAfterFirstUnlock استفاده کنید. هرگز از kSecAttrAccessibleAlways برای دادههای محرمانه استفاده نکنید.
توصیه میشود همیشه برای دادههایی که نیاز به همگامسازی ندارند، پسوند ThisDeviceOnly را اضافه کنید. این کار از کپی شدن تصادفی اسرار در iCloud یا iTunes backup جلوگیری میکند، جایی که ممکن است با ابزارهای تحلیل استخراج شوند. برای دادههای حیاتی، دسترسی را با kSecAccessControlUserPresence ترکیب کنید — این کار برای رمزگشایی رکورد نیاز به بیومتریک یا کد اضافه میکند.
هنگام استفاده از iCloud Keychain در نظر داشته باشید که رکوردهای همگامسازی شده در تمام دستگاههای کاربر در دسترس هستند: اگر مهاجم به یک دستگاه دسترسی پیدا کند، دادهها ممکن است در همه دستگاهها به خطر بیفتند. برای اسرار ایزوله از ThisDeviceOnly استفاده کنید.
سوالات متداول
UserDefaults دادهها را به صورت باز در فایل .plist ذخیره میکند که در تحلیل IPA قابل دسترس است. Keychain هر رکورد را جداگانه رمزگذاری میکند، از رمزگذاری سختافزاری استفاده میکند و از سطوح دسترسی، بیومتریک و همگامسازی از طریق iCloud پشتیبانی میکند.
در شبیهساز iOS در هر اجرا Keychain پاک میشود. در دستگاه واقعی برنامه را حذف کنید — iOS تمام رکوردهای Keychain این توسعهدهنده را حذف میکند. برای پاک کردن انتخابی، SecItemDelete را با ویژگیهای مربوطه فراخوانی کنید.
بله، از طریق keychain access groups. برنامهها باید team ID یکسان در امضا و entitlements با keychain-access-groups یکسان داشته باشند. توسعهدهنده دسترسی مشترک را در Xcode Capabilities پیکربندی میکند.
اپل محدودیت دقیقی مستند نکرده است، اما در عمل توصیه میشود از ۱–۴ کیلوبایت در هر رکورد تجاوز نکنید. برای حجمهای بزرگ از رمزگذاری فایل و ذخیره کلید در Keychain و خود دادهها در Documents استفاده کنید.
در جیلبریک حفاظت Keychain کاهش مییابد، زیرا مهاجم دسترسی root دریافت میکند و میتواند Keychain SQLite را مستقیماً بخواند. برای دادههای حیاتی از رمزگذاری اضافی با کلید دریافتی از سرور استفاده کنید.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید