Sobes.tech
Middle

Πού θα αποθηκεύατε τα προστατευμένα δεδομένα του χρήστη;

sobes.tech AI

Απάντηση από AI

Για την αποθήκευση των προστατευμένων δεδομένων χρήστη σε iOS, θα χρησιμοποιούσα τα ακόλουθα μέρη, ανάλογα με τον τύπο των δεδομένων και το επίπεδο ασφαλείας:

  1. Keychain Services:

    • Ιδανικό για την αποθήκευση μικρών ποσοτήτων εμπιστευτικών πληροφοριών, όπως κωδικούς πρόσβασης, tokens αυθεντικοποίησης, κλειδιά κρυπτογράφησης.
    • Ο διακομιστής securityd διαχειρίζεται το keychain και αποθηκεύει δεδομένα σε κρυπτογραφημένη μορφή στον δίσκο.
    • Υποστηρίζει διάφορα επίπεδα προσβασιμότητας (π.χ., διαθέσιμο μόνο όταν η συσκευή είναι ξεκλείδωτη).
    • Τα δεδομένα συγχρονίζονται αυτόματα μέσω iCloud Keychain, εάν είναι ενεργοποιημένο.
    import Foundation
    import Security
    
    func savePassword(service: String, account: String, password: String) -> OSStatus {
        let data = password.data(using: .utf8)!
        let query: [String: Any] = [
            kSecClass as String: kSecClassGenericPassword,
            kSecAttrService as String: service,
            kSecAttrAccount as String: account,
            kSecValueData as String: data
        ]
    
        SecItemDelete(query as CFDictionary) // Διαγράφει την υπάρχουσα εγγραφή
        return SecItemAdd(query as CFDictionary, nil) // Προσθέτει νέα εγγραφή
    }
    
  2. Κρυπτογραφημένα Core Data / Realm:

    • Για την αποθήκευση δομημένων δεδομένων που απαιτούν κρυπτογράφηση σε επίπεδο βάσης δεδομένων.
    • Το Core Data υποστηρίζει εξωτερικές επεκτάσεις για κρυπτογράφηση (π.χ., RNCryptor).
    • Η βάση δεδομένων Realm διαθέτει ενσωματωμένη κρυπτογράφηση αρχείου.
    • Το κλειδί κρυπτογράφησης πρέπει να αποθηκεύεται στο Keychain.
    // Παράδειγμα αρχικοποίησης Realm με κρυπτογράφηση
    import RealmSwift
    
    func setupEncryptedRealm() throws {
        var config = Realm.Configuration()
        if let key = KeychainHelper.getRealmEncryptionKey() { // Λαμβάνουμε το κλειδί από το Keychain
            config.encryptionKey = key
        } else {
            // Δημιουργούμε νέο κλειδί, το αποθηκεύουμε στο Keychain και το χρησιμοποιούμε
            let newKey = NSMutableData(length: 64)!
            _ = SecRandomCopyBytes(kSecRandomDefault, newKey.length, newKey.mutableBytes)
            KeychainHelper.saveRealmEncryptionKey(key: newKey as Data)
            config.encryptionKey = newKey as Data
        }
    
        let realm = try Realm(configuration: config)
        // Χρησιμοποιούμε το Realm
    }
    
  3. API προστασίας αρχείων:

    • Για κρυπτογράφηση αρχείων που αποθηκεύονται στο σύστημα αρχείων της εφαρμογής.
    • Το iOS κρυπτογραφεί αυτόματα τα αρχεία σε επίπεδο συστήματος αρχείων με κλειδιά που διαχειρίζεται το Secure Enclave.
    • Μπορούν να οριστούν διάφοροι τρόποι προστασίας (π.χ., complete, completeUnlessOpen, completeUntilFirstUserAuthentication, none) για τον έλεγχο πρόσβασης ανάλογα με την κατάσταση κλειδώματος της συσκευής.
    func saveProtectedDataToFile(data: Data, fileName: String) throws {
        let fileManager = FileManager.default
        let urls = fileManager.urls(for: .documentDirectory, in: .userDomainMask)
        guard let documentDirectory = urls.first else { throw NSError(domain: "MyApp", code: 1, userInfo: [NSLocalizedDescriptionKey: "Δεν βρέθηκε ο φάκελος εγγράφων"]) }
    
        let fileURL = documentDirectory.appendingPathComponent(fileName)
    
        // Ορίζουμε τον τρόπο προστασίας
        let options: Data.WritingOptions = .atomicWrite
        let protectedOptions: Data.WritingOptions = options.union(.writingWithoutOverwriting) // Παράδειγμα, οι πραγματικές επιλογές προστασίας ορίζονται με τα χαρακτηριστικά αρχείου ή στο info.plist
    
        try data.write(to: fileURL, options: options)
    
        // Ορίζουμε τα χαρακτηριστικά προστασίας του συστήματος αρχείων (παράδειγμα)
        var attributes: [FileAttributeKey : Any] = [:]
        attributes[.protectionKey] = FileProtectionType.complete
        try fileManager.setAttributes(attributes, ofItemAtPath: fileURL.path)
    }
    
  4. Secure Enclave:

    • Υλικό-επεξεργαστής, απομονωμένος από τον κύριο επεξεργαστή, προορισμένος για την αποθήκευση και επεξεργασία κρυπτογραφικών κλειδιών και δεδομένων.
    • Χρησιμοποιείται για Touch ID / Face ID και άλλες ευαίσθητες λειτουργίες.
    • Τα κλειδιά που αποθηκεύονται στο Secure Enclave ποτέ δεν φεύγουν από αυτό και δεν είναι διαθέσιμα στον κύριο επεξεργαστή ή το λειτουργικό σύστημα.
    • Ιδανικό για τη δημιουργία, αποθήκευση και χρήση κλειδιών για υπογραφή ή κρυπτογράφηση, όπου η προστασία από λογισμικό επιθέσεις είναι σημαντική.
    import CryptoKit
    import LocalAuthentication
    
    func generateAndStoreKeyInSecureEnclave() throws -> P256.Signing.PrivateKey {
        let accessControl = SecAccessControlCreateWithFlags(
            kCFAllocatorDefault,
            kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, // Διαθέσιμο όταν έχει οριστεί κωδικός
            [.userPresence], // Απαιτείται αυθεντικοποίηση χρήστη (Touch ID/Face ID)
            nil
        )!
    
        let attributes: [String: Any] = [
            kSecAttrKeyType as String: kSecAttrKeyTypeECSECPrimeRandom,
            kSecAttrKeySizeInBits as String: 256,
            kSecAttrTokenID as String: kSecAttrTokenIDSecureEnclave,
            kSecPrivateKeyAttrs as String: [
                kSecAttrIsPermanent as String: true, // Το κλειδί θα είναι μόνιμο
                kSecAttrApplicationTag as String: "com.yourapp.signingkey".data(using: .utf8)!, // Μοναδική ετικέτα
                kSecAttrAccessControl as String: accessControl
            ]
        ]
    
        var error: Unmanaged<CFError>?
        guard let privateKey = SecKeyCreateRandomKey(attributes as CFDictionary, &error) else {
            throw error!.takeRetainedValue() as Error
        }
    
        // Μπορείτε να λάβετε τα κλειδιά από το Secure Enclave μέσω της ετικέτας για χρήση
        return try P256.Signing.PrivateKey(rawRepresentation: privateKeyData) // Παράδειγμα, απαιτεί μετατροπή από SecKey σε Data
    }
    

Η επιλογή του χώρου αποθήκευσης εξαρτάται από:

  • Το μέγεθος των δεδομένων (μικρό όγκο vs δομημένα δεδομένα).
  • Τον τύπο των δεδομένων (κωδικός πρόσβασης vs αρχείο vs κρυπτογραφικό κλειδί).
  • Το απαιτούμενο επίπεδο προστασίας.
  • Την ανάγκη συγχρονισμού μεταξύ συσκευών (Keychain).
  • Την ανάγκη αυθεντικοποίησης χρήστη για πρόσβαση (Secure Enclave, File Protection).