Sobes.tech
Middle

Kur saugotumėte naudotojo apsaugotus duomenis?

sobes.tech AI

Atsakymas iš AI

iOS saugojimo saugių duomenų vietos pasirinkimas priklauso nuo duomenų tipo ir saugumo lygio:

  1. Keychain Services:

    • Idealiai tinka mažo kiekio konfidencialios informacijos saugojimui, pvz., slaptažodžiams, autorizacijos ženkliukams, šifravimo raktams.
    • Sisteminis demonas securityd valdo keychain ir saugo duomenis šifruotame formate diske.
    • Palaiko įvairius prieinamumo lygius (pvz., prieinama tik įrenginio atrakintame režime).
    • Duomenys automatiškai sinchronizuojami per iCloud Keychain, jei įjungta.
    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) // Ištrina esamą įrašą
        return SecItemAdd(query as CFDictionary, nil) // Prideda naują įrašą
    }
    
  2. Encrypted Core Data / Realm:

    • Tinka struktūruotų duomenų saugojimui, reikalaujančių šifravimo bazės lygyje.
    • Core Data palaiko trečiųjų šalių plėtinius šifravimui (pvz., RNCryptor).
    • Realm duomenų bazė turi įmontuotą failo šifravimą.
    • Šifravimo raktas turi būti saugomas Keychain.
    // Realm šifravimo pavyzdys
    import RealmSwift
    
    func setupEncryptedRealm() throws {
        var config = Realm.Configuration()
        if let key = KeychainHelper.getRealmEncryptionKey() { // Gauti raktą iš Keychain
            config.encryptionKey = key
        } else {
            // Sugeneruoti naują raktą, išsaugoti ir naudoti
            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)
        // Naudoti Realm
    }
    
  3. File Protection APIs:

    • Failų šifravimui, saugomam programos failų sistemoje.
    • iOS automatiškai šifruoja failus failų sistemos lygyje, naudojant Secure Enclave valdomas raktus.
    • Gali būti nustatyti įvairūs apsaugos režimai (pvz., complete, completeUnlessOpen, completeUntilFirstUserAuthentication, none) priklausomai nuo įrenginio užrakinimo būsenos.
    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: "Dokumento katalogas nerastas"])
    
        let fileURL = documentDirectory.appendingPathComponent(fileName)
    
        // Nustatyti apsaugos režimą
        let options: Data.WritingOptions = .atomicWrite
        let protectedOptions: Data.WritingOptions = options.union(.writingWithoutOverwriting) // Pavyzdys, tikrosios apsaugos parinktys nustatomos failo atributais arba info.plist
    
        try data.write(to: fileURL, options: options)
    
        // Failo sistemos atributų nustatymas (pavyzdys)
        var attributes: [FileAttributeKey : Any] = [:]
        attributes[.protectionKey] = FileProtectionType.complete
        try fileManager.setAttributes(attributes, ofItemAtPath: fileURL.path)
    }
    
  4. Secure Enclave:

    • Aparatinis papildomas procesorius, atskirtas nuo pagrindinio procesoriaus, skirtas saugoti ir apdoroti kriptografinius raktus ir duomenis.
    • Naudojamas Touch ID / Face ID ir kitų jautrių operacijų atlikimui.
    • Raktai, saugomi Secure Enclave, niekada neišvyksta iš jos ir nėra prieinami pagrindiniam procesoriui ar operacinei sistemai.
    • Idealiai tinka generuoti, saugoti ir naudoti raktus parašui ar šifravimui, kai svarbi programinės įrangos atakų apsauga.
    import CryptoKit
    import LocalAuthentication
    
    func generateAndStoreKeyInSecureEnclave() throws -> P256.Signing.PrivateKey {
        let accessControl = SecAccessControlCreateWithFlags(
            kCFAllocatorDefault,
            kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, // Prieinama tik su slaptažodžiu
            [.userPresence], // Reikalaujama naudotojo autentifikacijos (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, // Raktas bus nuolatinis
                kSecAttrApplicationTag as String: "com.yourapp.signingkey".data(using: .utf8)!, // Unikalus žymeklis
                kSecAttrAccessControl as String: accessControl
            ]
        ]
    
        var error: Unmanaged<CFError>?
        guard let privateKey = SecKeyCreateRandomKey(attributes as CFDictionary, &error) else {
            throw error!.takeRetainedValue() as Error
        }
    
        // Galima gauti raktus iš Secure Enclave pagal žymeklį naudojimui
        return try P256.Signing.PrivateKey(rawRepresentation: privateKeyData) // Pavyzdys, reikalinga konversija iš SecKey į Data
    }
    

Pasirinkimas priklauso nuo:

  • Duomenų dydžio (mažas kiekis vs struktūruoti duomenys)
  • Duomenų tipo (slaptažodis vs failas vs kriptografinis raktas)
  • Reikalingo saugumo lygio
  • Sinchronizacijos tarp įrenginių poreikio (Keychain)
  • Naudotojo autentifikacijos poreikio (Secure Enclave, File Protection)