אחסון נתונים מאובטח ב- iOS

הגנה על נתוני משתמשים רגישים היא אחריות בסיסית של כל יישום iOS.בין אם אתה מאחסן אסימונים, מפתחות הצפנה או אישורים פרטיים, הפלטפורמה מספקת פתרון ייעודי של חומרה ממוקדת: ה-FLT:0KeychainFLT:1 שלא כמו FLT:0 או רשימת נכסים, Keychain מצפיפה נתונים במנוחה ואכיפת בקרת גישה קפדנית.

הבנת ה-iOS Keychain

Keychain היא מיכל אחסון מאובטח המנוהל על ידי מערכת ההפעלה.It מאחסנת פריטים קטנים, רגישים - כגון סיסמאות, מפתחות קריפטוגרפיים או תעודות - במאגר נתונים מוצפנים.הנתונים הכתובים ל- Keychain מוגנים גם כאשר המכשיר נעול.

  • (ב) ,0) , התגלות במנוחה: 1:1 באמצעות חומרה AES-256.
  • (ב) ,0) בקרת גישה (FLT:1) באמצעות קוד, Touch ID או Face ID.
  • (ב) [15] , ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇
  • (FLT:0)IsolationFLT:1 בין יישומים: כברירת מחדל, אפליקציה אחת לא יכולה לקרוא פריטים מרכזיים של אפליקציה אחרת אלא אם כן הם חולקים קבוצת גישה ל- Keychain.

ה- Keychain אינה מיועדת לנפיחות גדולה; שמור כל פריט תחת כמה קילובייטים.עבור נתונים גדולים יותר, שקול להשתמש ב-FLT:1 או ב-APFLT:2 מסגרת יחד עם הצפנה מבוססת קבצים.

Keychain Services API לעומת חתלתת צד שלישי

אפל מספקת את NativeFLT:0. [WEB שירותים של שרשרת] 1 API (C-based, FLT 3: 3), אשר הוא חזק אך פועלו, ניתן להשתמש בו ישירות, או לאמץ ספריה ידידותית סוויפט (C- צד שלישי פופולרי כגון FLT:2Keychain AccessFLT 3: או FLT:4SwiftchainWraperFLT: 5.

הקמת אחסון Keychain

לפני אחסון כל דבר, עליך להחליט על שיעור הפריט של 0.10.1.10.1. [הנפוץ ביותר עבור סיסמאות גנריות הוא FLT:4 [עבור סיסמאות אינטרנט או תעודות, יש שיעורים אחרים.כל פריט מתייחס על ידי קבוצה של תכונות - מילון (CFDictionary) המתאר את הפריט.

זרימת הבסיס תמיד עוקבת אחר דפוס זה:

  1. בנו מילון שאילתה עם שיעור הפריט ותכונות.
  2. (ב) ויקרא ה' (ב') ויקרא (בראשית י"ד, כ"ד)
  3. ראה את ה-FLT:10 (ראה: 11) או קוד שגיאה.

לפני כתיבת קוד, לייבא את מודול האבטחה:

import Security
import Foundation // for Data and String utilities

איסוף נתונים ב- Keychain

לכתוב סיסמה ג'נרית

כדי לחסוך אסימונים (למשל, JWT) למשתמש הנוכחי:

func saveToken(_ token: String, forAccount account: String) -> Bool {
 guard let tokenData = token.data(using: .utf8) else { return false }

 let query: [String: Any] = [
 kSecClass as String: kSecClassGenericPassword,
 kSecAttrAccount as String: account,
 kSecValueData as String: tokenData,
 // Optional: restrict access to when device is unlocked
 kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlockedThisDeviceOnly
 ]

 // Delete any existing item first to avoid duplicates
 SecItemDelete(query as CFDictionary)

 let status = SecItemAdd(query as CFDictionary, nil)
 return status == errSecSuccess
}

נקודות מפתח:

  • (ב) , (ב) , ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇
  • (FLT:16 בקרות כאשר ניתן לקרוא את הפריט, השתמש ב-FLT:17 עבור אבטחה הטובה ביותר; זה מונע גיבוי iCloud ומגביל גישה למכשיר הנוכחי.
  • אנו קוראים ל-FLT:18 לפני הוספת פריטים כפולים, לחלופין, אתה יכול להשתמש ב- 19.

בקרת גישה (Biometry או Passcode)

לקבלת נתונים רגישים מאוד, דורש זיהוי מגע או Face ID לפני קריאה:

let accessControl = SecAccessControlCreateWithFlags(
 nil,
 kSecAttrAccessibleWhenUnlockedThisDeviceOnly,
 .userPresence, // requires passcode, Face ID, or Touch ID
 nil
)

let query: [String: Any] = [
 kSecClass as String: kSecClassGenericPassword,
 kSecAttrAccount as String: account,
 kSecValueData as String: tokenData,
 kSecAttrAccessControl as String: accessControl as Any
]
SecItemAdd(query as CFDictionary, nil)

כעת, כל קריאה לסעיף זה תפעיל ביומטרי או קוד דרך (FLT:22) מההתאמת המקומית כדי להתמודד עם אינטראקציה המשתמש בחסד.

שחזור נתונים מהמפתח

לקרוא את הסימון המאוחסן:

func retrieveToken(forAccount account: String) -> String? {
 let query: [String: Any] = [
 kSecClass as String: kSecClassGenericPassword,
 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,
 let data = item as? Data,
 let token = String(data: data, encoding: .utf8) else {
 return nil
 }
 return token
}

(ב) ,(ה) , עיין ב-[[1924]], ב[[1924]], ב[[1924]], ב[[1924]], ב[[1924]], [[1924]], [[1924]],]], [[1924]],]], [[1924]],]], [[1924]],]], [[1924]],]]

(ב) ויקרא ה': ויקרא ה': "בְּהַּהְיִלְתָּעָה אִם עַל עַמֶּה הוּא הוּא הוּא הוּא הוּא הוּא הוּא וּכְתָּעָעָשָׂעָעָעָעָעָעָעָשָׂרָה"ל אִם הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא

פריטים ומחקו את Keychain

העלאתם של

במקום לפוצץ ולרצות, להשתמש ב-FLT:29:

func updateToken(_ newToken: String, forAccount account: String) -> Bool {
 guard let newData = newToken.data(using: .utf8) else { return false }

 let query: [String: Any] = [
 kSecClass as String: kSecClassGenericPassword,
 kSecAttrAccount as String: account
 ]

 let attributesToUpdate: [String: Any] = [
 kSecValueData as String: newData
 ]

 let status = SecItemUpdate(query as CFDictionary, attributesToUpdate as CFDictionary)
 return status == errSecSuccess
}

זה יעיל יותר מאשר למחוק +add, וזה נמנע מתנאי גזע פוטנציאליים.

מחיקתם של

func deleteItem(forAccount account: String) -> Bool {
 let query: [String: Any] = [
 kSecClass as String: kSecClassGenericPassword,
 kSecAttrAccount as String: account
 ]
 let status = SecItemDelete(query as CFDictionary)
 return status == errSecSuccess
}

היזהרו לא למחוק פריטים השייכים לאפליקציות אחרות שחולקים את אותה קבוצת גישה – תמיד מבססים את השאילתה שלכם עם ההרחבה המשותפת של ה-FLT:32 אם אתם משתמשים ב- Keychains.

בקרת גישה ו- Access Access Attributes

(הופנה מהדף ההרחבה "FLT:0"(כאשר ⁇ FLT:1) ניתן לקרוא את פריט Keychain.בחר את האפשרות המגבילה ביותר שעדיין עונה על צרכי האפליקציה שלך:

AttributeMeaning
kSecAttrAccessibleWhenUnlockedAvailable only while device is unlocked (default).
kSecAttrAccessibleAfterFirstUnlockAvailable after device boots and is unlocked once. Allows background access.
kSecAttrAccessibleWhenPasscodeSetThisDeviceOnlyRequires a passcode to be set. Strictest option—prevents access even after unlock if passcode is removed.
kSecAttrAccessibleWhenUnlockedThisDeviceOnlySame as WhenUnlocked but does not back up to iCloud, and cannot be restored to another device.

עבור רוב האפליקציות, ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇

טעויות ומלכודות נפוצות

הפונקציות של ה-FLT:41 מחזירות את ה-FLT:42 תמיד לבדוק את זה ולטפל בכישלונות כראוי.

  • (ב) לא יתאים כלל פריט לשאילתה.
  • (FLT:44) (-299-25) – פריט בעל אותו מפתח כבר קיים (אם לא מחקת קודם).
  • (FLT:45) (-128) – המשתמש ביטל את המהירות הביומטרית.
  • (ב- 25293) – Authentication נכשלה או ביומטריות לא זמינות.

לעולם אל תתעלם ממעמד שאינו עולה בקנה מידה: להציג הודעת שגיאה או ניסיון, אך לעולם אל תחסנו נתונים רגישים מחוץ ל- Keychain כנפילה.You can use FLT:47 כדי לבדוק זמינות ביומטרית לפני ניסיון גישה.

שיטות ושיקולי ייצור הטובים ביותר

  • (ב) שמות תיאורים ייחודיים, תיאוריים: 1) למשתמש או לסוג פריט כדי להימנע מהתנגשות.
  • (ב) ויקרא י"א): "ה', ב'"ה', ב'"ה', ב'"ה', ב'"ה', לא יכפר על ה'.
  • (ב) עיין ב-[[1924]], [[1924]], [[1924]]]], [[1924]]]], [[1924]]]]]]
  • (ב) ,0) קבוצות הגישה של Keychain Access GroupsFLT:1 רק כאשר שיתוף בין היישומים שלך.
  • (ב) [ה]ה] לא תקנו נתונים שאינם רגישים ל-[[המאה ה-1]], אלא כהעדפות משתמשים) ב- Keychain – שימוש ב-FLT:49 או במסד נתונים.
  • (ב) ,0) ,2 (בשיתוף) עם ⁇ (FLT:51) ,(FLT 1: 1) עבור תרחישים מתקדמים (מקOS Catalyst).
  • (ב) ,0) ,Test במכשיר אמיתי FLT:1; הסימול משתמש בתוכנה Keychain שפועלת אחרת מאחסון מוגן בחומרה.

שימוש ב- Keychain עם SwiftUI ו- Async/Await

עבור יישומים מודרניים, עוטפים את פעולות Keychain לשחקן או בכיתה בטוחה של חץ כדי למנוע חסימת החוט הראשי.

actor KeychainManager {
 func saveToken(_ token: String, for account: String) async -> Bool {
 // same implementation as above, but now it's safe to call from any context
 return saveToken(token, forAccount: account)
 }
}

אם אתה משתמש ביומטריות, שיחת FLT:54 עשויה לחסום את החוט בעת ההמתנה לאינטראקציה של משתמשים.

מסקנה

The iOS Keychain is the correct place to store small, sensitive pieces of data. By using the native Keychain Services API, you gain direct control over encryption, accessibility, and authentication policies. Always pair your Keychain usage with solid error handling and remember to clear data when appropriate. For further reading, refer to the Apple Keychain Service Documentation and the Keychain Concepts overview. Adopting these practices will help you ship iOS apps that respect user privacy and withstand security scrutiny.