Keychain στο iOS: τι είναι, αρχιτεκτονική και εργασία με μυστικά

Συγγραφέας: IT Sectr Δημοσιεύτηκε: 2026-04-04 Χρόνος ανάγνωσης: 9 λεπ

Keychain (Αλυσίδα Κλειδιών) — ένα ασφαλές αποθετήριο στο iOS, σχεδιασμένο για την ασφαλή αποθήκευση κωδικών πρόσβασης, κρυπτογραφικών κλειδιών, πιστοποιητικών και εμπιστευτικών σημειώσεων. Σύμφωνα με την Apple Security Documentation (2025), το Keychain χρησιμοποιεί υλικό κρυπτογράφησης μέσω του Secure Enclave σε όλες τις συσκευές με τσιπ A7 και νεότερες. Η κατανόηση της αρχιτεκτονικής iOS Keychain είναι απαραίτητη για κάθε προγραμματιστή για τη σωστή αποθήκευση tokens και μυστικών της εφαρμογής.

Βασικά Σημεία

  • iOS Keychain — μια κρυπτογραφημένη βάση δεδομένων SQLite για αποθήκευση μυστικών με προστασία υλικού μέσω του Secure Enclave.
  • Protection Class καθορίζει πότε τα δεδομένα είναι διαθέσιμα: όταν η συσκευή είναι ξεκλείδωτη, μετά το πρώτο ξεκλείδωμα ή πάντα.
  • Access Control List (ACL) — ένας μηχανισμός περιορισμού πρόσβασης σε στοιχεία του Keychain, συμπεριλαμβανομένου του βιομετρικού ελέγχου ταυτότητας.
  • SecItemAdd και SecItemCopyMatching — τα κύρια API του Security framework για εγγραφή και ανάγνωση στοιχείων.
  • kSecAttrSynchronizable — μια σημαία που επιτρέπει τον συγχρονισμό του Keychain μέσω iCloud για πρόσβαση σε όλες τις συσκευές του χρήστη.

Τι είναι το Keychain στο iOS;

iOS Keychain — ένας ασφαλής μηχανισμός αποθήκευσης εμπιστευτικών δεδομένων, ενσωματωμένος στο λειτουργικό σύστημα της Apple. Σε αντίθεση με τα UserDefaults ή τα κανονικά αρχεία, το Keychain κρυπτογραφεί όλα τα στοιχεία σε επίπεδο υλικού και παρέχει λεπτομερή έλεγχο πρόσβασης βάσει πολιτικών ασφαλείας.

Το Keychain παρουσιάστηκε στο iOS 2.0 και από τότε έχει υποστεί σημαντικές αλλαγές: στο iOS 7 προστέθηκε υποστήριξη για υλικό κλειδιά μέσω του Secure Enclave, στο iOS 9 — διαχωρισμός του Keychain μεταξύ εφαρμογών μέσω Access Groups, στο iOS 13 — υποστήριξη βιομετρικής σύνδεσης μέσω LAContext. Σύμφωνα με το Apple WWDC Session (2024), πάνω από το 90% των iOS εφαρμογών στο top-100 του App Store χρησιμοποιούν το Keychain για αποθήκευση tokens ελέγχου ταυτότητας.

Αρχιτεκτονικά, το Keychain είναι μια κρυπτογραφημένη βάση δεδομένων SQLite, που βρίσκεται εκτός του sandbox της εφαρμογής. Κάθε στοιχείο (SecItem) κρυπτογραφείται με ξεχωριστό κλειδί, το οποίο με τη σειρά του προστατεύεται από ένα υλικό κλειδί του Secure Enclave. Η υπηρεσία συστήματος Securityd διαχειρίζεται την πρόσβαση στο Keychain βάσει των δικαιωμάτων της εφαρμογής (entitlements) και της ζητούμενης κλάσης προστασίας.

Ένα σημαντικό πλεονέκτημα του Keychain έναντι άλλων τρόπων αποθήκευσης: τα δεδομένα κρυπτογραφούνται και αποκρυπτογραφούνται αυτόματα από το ΛΣ. Ο προγραμματιστής δεν χρειάζεται να υλοποιήσει κρυπτογραφία χειροκίνητα — αρκεί να καλέσει το SecItemAdd με τις σωστές παραμέτρους. Το iOS εγγυάται ότι τα δεδομένα από το Keychain δεν μπορούν να διαβαστούν από άλλες εφαρμογές (με τη σωστή ρύθμιση των Access Groups).

Αρχιτεκτονική του Keychain

Η αρχιτεκτονική Keychain περιλαμβάνει αρκετά επίπεδα: φυσικό (Secure Enclave), συστημικό (Security.framework), εφαρμοσμένο (API SecItem*) και λογικό (Access Groups, Protection Classes). Η κατανόηση κάθε επιπέδου βοηθά στο σωστό σχεδιασμό αποθήκευσης μυστικών.

SecItemAdd και SecItemCopyMatching

Το βασικό API για εργασία με το Keychain είναι οι συναρτήσεις του Security framework: SecItemAdd για προσθήκη, SecItemCopyMatching για ανάγνωση, SecItemUpdate για ενημέρωση και SecItemDelete για διαγραφή. Κάθε συνάρτηση δέχεται ένα λεξικό query, το οποίο περιγράφει τα γνωρίσματα του αναζητούμενου ή αποθηκευόμενου στοιχείου.

Βασικά γνωρίσματα query: kSecClass — τύπος στοιχείου (kSecClassGenericPassword, kSecClassKey, kSecClassCertificate), kSecAttrAccount — μοναδικό αναγνωριστικό εντός της κλάσης, kSecValueData — αποθηκευόμενα δεδομένα (Data), kSecAttrAccessible — κλάση προστασίας. SecItemCopyMatching με τη σημαία kSecReturnData επιστρέφει τα δεδομένα του στοιχείου, με το kSecMatchLimit — τον αριθμό των αποτελεσμάτων.

Σημαντικό: όλες οι συναρτήσεις επιστρέφουν κατάσταση OSStatus. Μια επιτυχημένη λειτουργία επιστρέφει errSecSuccess (0). Σφάλματα: errSecItemNotFound (-25300) — το στοιχείο δεν βρέθηκε, errSecDuplicateItem (-25299) — το στοιχείο υπάρχει ήδη, errSecAuthFailed (-25293) — η βιομετρική επαλήθευση απέτυχε. Ο προγραμματιστής πρέπει να χειρίζεται σωστά κάθε κατάσταση.

Κλάσεις προστασίας (Protection Class)

Protection Class — το γνώρισμα kSecAttrAccessible, το οποίο καθορίζει πότε τα δεδομένα στο Keychain είναι διαθέσιμα για ανάγνωση. Το iOS υποστηρίζει έξι κλάσεις προστασίας με διαφορετικό επίπεδο διαθεσιμότητας και ασφάλειας.

Η συνιστώμενη κλάση για τα περισσότερα σενάρια είναι η kSecAttrAccessibleWhenUnlockedThisDeviceOnly: τα δεδομένα είναι διαθέσιμα μόνο όταν η συσκευή είναι ξεκλείδωτη και δεν αντιγράφονται στο iCloud Backup. Για δεδομένα που πρέπει να είναι διαθέσιμα μετά από επανεκκίνηση (αλλά μόνο μετά το πρώτο ξεκλείδωμα), χρησιμοποιήστε kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly. Για κρίσιμα δεδομένα που απαιτούν βιομετρική επαλήθευση σε κάθε πρόσβαση, συνδυάστε το kSecAttrAccessibleWhenUnlockedThisDeviceOnly με ACL που απαιτεί biometry.

Οι κλάσεις χωρίς το επίθεμα ThisDeviceOnly (kSecAttrAccessibleWhenUnlocked, kSecAttrAccessibleAfterFirstUnlock) επιτρέπουν την αντιγραφή στο iCloud Backup. Αυτό είναι βολικό για τον χρήστη, αλλά μειώνει την ασφάλεια — τα δεδομένα μπορούν να αποκατασταθούν από το αντίγραφο ασφαλείας. Για τα tokens ελέγχου ταυτότητας, χρησιμοποιείτε πάντα ThisDeviceOnly.

Access Control Lists (ACL)

Access Control List (ACL) — ένας μηχανισμός που περιορίζει τις λειτουργίες σε ένα στοιχείο Keychain βάσει της επαλήθευσης του χρήστη. Το ACL ορίζεται μέσω SecAccessControlCreateWithFlags και μεταβιβάζεται στο γνώρισμα kSecAttrAccessControl κατά την αποθήκευση του στοιχείου.

Υποστηριζόμενες σημαίες: kSecAccessControlUserPresence — οποιαδήποτε επαλήθευση (Face ID, Touch ID ή κωδικός πρόσβασης), kSecAccessControlBiometryCurrentSet — μόνο βιομετρία (τα τρέχοντα καταχωρημένα δακτυλικά αποτυπώματα ή πρόσωπο), kSecAccessControlDevicePasscode — μόνο κωδικός πρόσβασης. Το ACL εφαρμόζεται σε κάθε λειτουργία: η ανάγνωση, η ενημέρωση και η διαγραφή του στοιχείου απαιτούν επίσης επαλήθευση.

Στο iOS 15+ προστέθηκε η σημαία kSecAccessControlWatch — για Apple Watch, η οποία επιτρέπει την επαλήθευση μέσω του συνδεδεμένου ρολογιού. Το ACL μπορεί να συνδυαστεί: για παράδειγμα, kSecAccessControlUserPresence ή kSecAccessControlBiometryAny με προαιρετικό κωδικό πρόσβασης (προσανατολισμός .or).

Τύποι δεδομένων στο Keychain

iOS Keychain υποστηρίζει τέσσερις βασικές κλάσεις στοιχείων (kSecClass), κάθε μία προορισμένη για τον δικό της τύπο δεδομένων. Η σωστή επιλογή κλάσης απλοποιεί την οργάνωση και την αναζήτηση στοιχείων.

kSecClassGenericPassword — γενικός κωδικός πρόσβασης: η πιο συχνά χρησιμοποιούμενη κλάση. Αποθηκεύει οποιαδήποτε δυαδικά δεδομένα (Data) με ένα μοναδικό κλειδί (kSecAttrAccount). Είναι κατάλληλη για tokens, κλειδιά API, PIN κωδικούς. Δεν απαιτεί επιπλέον entitlements για χρήση.

kSecClassInternetPassword — κωδικός διαδικτύου: αποθηκεύει δεδομένα που σχετίζονται με έναν δικτυακό πόρο. Επιπλέον γνωρίσματα: kSecAttrServer (τομέας διακομιστή), kSecAttrProtocol (https, ftp), kSecAttrPort, kSecAttrAuthenticationType. Το iOS μπορεί να συμπληρώσει αυτόματα τέτοιους κωδικούς μέσω AutoFill.

kSecClassKey — κρυπτογραφικό κλειδί: για αποθήκευση κλειδιών κρυπτογράφησης (AES, RSA, EC). Το κλειδί αποθηκεύεται ως SecKeyRef, όχι ως Data. kSecClassCertificate — πιστοποιητικό X.509 για αποθήκευση και επαλήθευση ψηφιακών πιστοποιητικών. Και οι δύο κλάσεις απαιτούν κατανόηση των κρυπτογραφικών λειτουργιών και σωστή ρύθμιση των γνωρισμάτων.

Στην πράξη, το 95% των περιπτώσεων χρήσης του Keychain σε κινητές εφαρμογές καλύπτονται από το kSecClassGenericPassword για αποθήκευση tokens ελέγχου ταυτότητας και από το kSecClassKey για αποθήκευση ιδιωτικών κλειδιών κρυπτογράφησης. Το kSecClassCertificate χρησιμοποιείται σπάνια — συνήθως σε επιχειρηματικές εφαρμογές με ιδιωτικό PKI.

Παραδείγματα κώδικα: εργασία με το Keychain σε Swift

Ας δούμε πρακτικά παραδείγματα εργασίας με το Keychain σε Swift χρησιμοποιώντας το Security framework. Κάθε παράδειγμα περιλαμβάνει διαχείριση σφαλμάτων και σωστή ρύθμιση Protection Class.

Αποθήκευση και ανάγνωση token

Το βασικό παράδειγμα αποθηκεύει ένα token ελέγχου ταυτότητας στο Keychain με προστασία WhenUnlockedThisDeviceOnly. Το κλειδί (kSecAttrAccount) είναι το αναγνωριστικό υπηρεσίας, τα δεδομένα (kSecValueData) είναι το token σε μορφή Data.

swift
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)
}

Αποθήκευση με βιομετρική σύνδεση

Το παράδειγμα δείχνει τη χρήση SecAccessControlCreateWithFlags για τη σύνδεση του κλειδιού με τη βιομετρία. Κάθε πρόσβαση στο στοιχείο θα απαιτεί Face ID ή Touch ID.

swift
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)
    }
}

Keychain Sharing μεταξύ εφαρμογών

Το παράδειγμα δείχνει τη ρύθμιση Access Group για κοινή πρόσβαση στο Keychain μεταξύ εφαρμογών του ίδιου προγραμματιστή. Απαιτείται entitlement keychain-access-groups.

swift
// Capabilities: Το Keychain Sharing είναι ενεργοποιημένο
// 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)
}

Βέλτιστες πρακτικές εργασίας με το Keychain

Η σωστή χρήση του iOS Keychain απαιτεί τήρηση αρκετών βασικών κανόνων που αποτρέπουν τυπικές ευπάθειες και απώλεια δεδομένων.

Χρησιμοποιείτε ThisDeviceOnly για όλα τα μυστικά ελέγχου ταυτότητας: το kSecAttrAccessibleWhenUnlockedThisDeviceOnly εγγυάται ότι τα tokens δεν θα καταλήξουν στο iCloud Backup. Αν ένας εισβολέας αποκτήσει πρόσβαση στο αντίγραφο ασφαλείας, τα δεδομένα Keychain με αυτή τη σημαία δεν θα είναι διαθέσιμα. Εξαίρεση αποτελούν τα δεδομένα που πρέπει να είναι διαθέσιμα σε όλες τις συσκευές του χρήστη (για παράδειγμα, κλειδιά κρυπτογράφησης για ιδιωτικές υπηρεσίες), για τα οποία χρησιμοποιείτε kSecAttrAccessibleWhenUnlocked με kSecAttrSynchronizable.

Μην αποθηκεύετε αρχικούς κωδικούς πρόσβασης — αποθηκεύετε hashes ή tokens συνεδρίας. Apple Security Guide (2025) συνιστά να μην αποθηκεύετε ποτέ τον κωδικό πρόσβασης του χρήστη στο Keychain σε απλή μορφή. Αντί αυτού, αποθηκεύετε το refresh token που λάβατε από τον διακομιστή μετά από επιτυχημένη επαλήθευση μέσω OAuth 2.0. Ο κωδικός πρόσβασης χρησιμοποιείται μόνο για τη λήψη του token και διαγράφεται αμέσως από τη μνήμη.

Χειρίζεστε σωστά τα σφάλματα του Keychain: κάθε λειτουργία στο Keychain επιστρέφει OSStatus, το οποίο πρέπει να ελέγχεται. Ιδιαίτερη προσοχή στα errSecItemNotFound (το token έληξε ή διαγράφηκε) και errSecAuthFailed (η βιομετρία απέτυχε). Στην πρώτη περίπτωση, η εφαρμογή πρέπει να ζητήσει νέα επαλήθευση, στη δεύτερη — να εμφανίσει στον χρήστη εναλλακτικό τρόπο (κωδικό πρόσβασης). Ποτέ μην αγνοείτε την κατάσταση errSecItemNotFound — αυτό θα οδηγήσει σε σφάλμα της εφαρμογής κατά την προσπάθεια ανάγνωσης nil.

Δοκιμάστε το Keychain σε πραγματική συσκευή: ο προσομοιωτής δεν έχει Secure Enclave και δεν υποστηρίζει βιομετρικά ACL. Πάντα ελέγχετε τα σενάρια: πρώτη εκκίνηση, επαναφορά από αντίγραφο ασφαλείας, αλλαγή κωδικού πρόσβασης συσκευής, διαγραφή και επανεγκατάσταση εφαρμογής. Σε πραγματική συσκευή, το Keychain διατηρείται κατά τη διαγραφή της εφαρμογής, αλλά μόνο αν δεν χρησιμοποιήθηκε η σημαία kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, η οποία καθαρίζεται κατά την αφαίρεση του κωδικού πρόσβασης.

Ελαχιστοποιήστε τον αριθμό λειτουργιών με το Keychain: κάθε λειτουργία ανάγνωσης ή εγγραφής είναι μια κλήση στην υπηρεσία συστήματος Securityd, η οποία μπορεί να μπλοκάρει το νήμα. Προσωρινά αποθηκεύστε τα διαβασμένα tokens στη μνήμη για τη διάρκεια της συνεδρίας και επιστρέψτε στο Keychain ξανά μόνο κατά την επανεκκίνηση της εφαρμογής ή σφάλμα επαλήθευσης (401 από τον διακομιστή). iOS αυτόματα κλειδώνει το Keychain κατά το κλείδωμα της συσκευής, οπότε προγραμματίστε την ανάγνωση μέσω LAContext με αίτημα βιομετρίας.

Συχνές Ερωτήσεις

Μπορώ να αποθηκεύσω δεδομένα στο Keychain και να τα διαβάσω μετά από επανεκκίνηση;

Ναι, χρησιμοποιήστε την κλάση προστασίας kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly ή kSecAttrAccessibleAfterFirstUnlock. Τα δεδομένα θα είναι διαθέσιμα μετά το πρώτο ξεκλείδωμα της συσκευής μετά την επανεκκίνηση. Για αυτόματη πρόσβαση κατά την εκκίνηση της εφαρμογής (χωρίς αναμονή ξεκλειδώματος) χρησιμοποιήστε kSecAttrAccessibleAlways, αλλά αυτό μειώνει την ασφάλεια.

Πώς να καθαρίσω το Keychain κατά την αποσύνδεση χρήστη;

Καλέστε SecItemDelete με query που περιέχει kSecClass για κάθε τύπο δεδομένων. Για πλήρη καθαρισμό όλων των στοιχείων της εφαρμογής εκτελέστε: SecItemDelete([kSecClass as String: kSecClassGenericPassword] as CFDictionary). Επαναλάβετε για kSecClassKey, kSecClassCertificate και kSecClassInternetPassword.

Ποια είναι η διαφορά μεταξύ kSecAttrAccessible και kSecAttrAccessControl;

kSecAttrAccessible καθορίζει πότε τα δεδομένα είναι διαθέσιμα (κατά το ξεκλείδωμα, μετά το πρώτο ξεκλείδωμα κ.λπ.). kSecAttrAccessControl καθορίζει ποιος μπορεί να αποκτήσει πρόσβαση (βιομετρία, κωδικός πρόσβασης, οποιαδήποτε επαλήθευση). Συνδυάζονται: πρώτα Protection Class, μετά ACL. Για παράδειγμα, τα δεδομένα είναι διαθέσιμα μόνο κατά το ξεκλείδωμα ΚΑΙ μόνο μετά από Face ID.

Γιατί το SecItemCopyMatching επιστρέφει errSecItemNotFound;

Αιτίες: το στοιχείο δεν αποθηκεύτηκε ποτέ, το στοιχείο διαγράφηκε κατά την αφαίρεση του κωδικού πρόσβασης (αν χρησιμοποιήθηκε kSecAttrAccessibleWhenPasscodeSet), η εφαρμογή επανεγκαταστάθηκε (το Keychain διατηρείται αλλά δεν αποκαθίσταται από το αντίγραφο ασφαλείας σε νέα συσκευή), άλλαξε το Access Group ή το αναγνωριστικό ομάδας προγραμματιστή. Ελέγξτε τα kSecAttrService και kSecAttrAccount.

Πώς να ελέγξω αν η συσκευή υποστηρίζει βιομετρία στο Keychain;

Χρησιμοποιήστε LAContext από το LocalAuthentication: καλέστε context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: nil). Αν επιστρέφει true — η συσκευή υποστηρίζει Touch ID ή Face ID. Για Keychain ACL χρησιμοποιήστε τη σημαία biometryCurrentSet (μόνο τρέχοντα βιομετρικά δεδομένα) ή biometryAny (οποιαδήποτε καταχωρημένα προηγουμένως).

Συμπεράσματα

  • iOS Keychain — αποθηκευτικός χώρος προστατευμένος από υλικό για μυστικά με κρυπτογράφηση μέσω Secure Enclave και έλεγχο πρόσβασης μέσω ACL.
  • Security framework παρέχει τις συναρτήσεις SecItemAdd, SecItemCopyMatching, SecItemUpdate και SecItemDelete για εργασία με στοιχεία.
  • Protection Class (kSecAttrAccessible) επιλέγεται βάσει σεναρίου: WhenUnlockedThisDeviceOnly — πρότυπο για tokens.
  • ACL με βιομετρία (kSecAttrAccessControl) προσθέτει απαίτηση Face ID ή Touch ID για κάθε λειτουργία ανάγνωσης.
  • kSecClassGenericPassword καλύπτει το 95% των περιπτώσεων — αποθήκευση tokens, κλειδιών API, PIN κωδικών και σημειώσεων.
  • ThisDeviceOnly αποτρέπει την αντιγραφή μυστικών στο iCloud Backup — υποχρεωτικό για tokens ελέγχου ταυτότητας.
  • Σωστός χειρισμός OSStatus και δοκιμές σε πραγματική συσκευή — υποχρεωτικές πρακτικές για αξιόπιστη εργασία με το Keychain.

Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση

Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.

Συζήτηση έργου

Διαβάστε επίσης