Middle
Gdzie przechowywałbyś chronione dane użytkownika?
sobes.tech AI
Odpowiedź od AI
Aby przechowywać chronione dane użytkownika na iOS, użyłbym następujących miejsc, w zależności od typu danych i poziomu bezpieczeństwa:
-
Keychain Services:
- Idealne do przechowywania niewielkich ilości poufnych informacji, takich jak hasła, tokeny autoryzacyjne, klucze szyfrowania.
- Systemowy demon
securitydzarządza keychain i przechowuje dane w zaszyfrowanej formie na dysku. - Obsługuje różne poziomy dostępności (np. dostępne tylko przy odblokowanym urządzeniu).
- Dane są automatycznie synchronizowane przez iCloud Keychain, jeśli jest włączone.
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) // Usuwamy istniejący wpis return SecItemAdd(query as CFDictionary, nil) // Dodajemy nowy wpis } -
Zaszyfrowane Core Data / Realm:
- Do przechowywania danych strukturalnych, wymagających szyfrowania na poziomie bazy danych.
- Core Data obsługuje zewnętrzne rozszerzenia do szyfrowania (np. RNCryptor).
- Realm Database ma wbudowane szyfrowanie pliku bazy danych.
- Klucz szyfrowania musi być przechowywany w Keychain.
// Przykład inicjalizacji Realm z szyfrowaniem import RealmSwift func setupEncryptedRealm() throws { var config = Realm.Configuration() if let key = KeychainHelper.getRealmEncryptionKey() { // Pobieramy klucz z Keychain config.encryptionKey = key } else { // Generujemy nowy klucz, zapisujemy go w Keychain i używamy 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) // Używamy Realm } -
API ochrony plików:
- Do szyfrowania plików przechowywanych w systemie plików aplikacji.
- iOS automatycznie szyfruje pliki na poziomie systemu plików za pomocą kluczy zarządzanych przez Secure Enclave.
- Można ustawić różne tryby ochrony (np.
complete,completeUnlessOpen,completeUntilFirstUserAuthentication,none) dla kontroli dostępu w zależności od stanu blokady urządzenia.
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: "Nie znaleziono katalogu dokumentów"]) } let fileURL = documentDirectory.appendingPathComponent(fileName) // Ustawiamy tryb ochrony let options: Data.WritingOptions = .atomicWrite let protectedOptions: Data.WritingOptions = options.union(.writingWithoutOverwriting) // Przykład, rzeczywiste opcje ochrony ustawiane są atrybutami pliku lub w info.plist try data.write(to: fileURL, options: options) // Ustawianie atrybutów ochrony systemu plików (przykład) var attributes: [FileAttributeKey : Any] = [:] attributes[.protectionKey] = FileProtectionType.complete try fileManager.setAttributes(attributes, ofItemAtPath: fileURL.path) } -
Secure Enclave:
- Sprzętowy koprocesor, odseparowany od głównego procesora, przeznaczony do przechowywania i obsługi kluczy kryptograficznych oraz danych.
- Używany do Touch ID / Face ID i innych wrażliwych operacji.
- Klucze przechowywane w Secure Enclave nigdy nie opuszczają jej i nie są dostępne dla głównego procesora ani systemu operacyjnego.
- Idealnie nadaje się do generowania, przechowywania i używania kluczy do podpisu lub szyfrowania, gdzie ważna jest ochrona przed atakami programowymi.
import CryptoKit import LocalAuthentication func generateAndStoreKeyInSecureEnclave() throws -> P256.Signing.PrivateKey { let accessControl = SecAccessControlCreateWithFlags( kCFAllocatorDefault, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, // Dostępne przy ustawionym haśle [.userPresence], // Wymaga uwierzytelnienia użytkownika (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, // Klucz będzie trwały kSecAttrApplicationTag as String: "com.yourapp.signingkey".data(using: .utf8)!, // Unikalny tag kSecAttrAccessControl as String: accessControl ] ] var error: Unmanaged<CFError>? guard let privateKey = SecKeyCreateRandomKey(attributes as CFDictionary, &error) else { throw error!.takeRetainedValue() as Error } // Można uzyskać klucze z Secure Enclave po tagu do użycia return try P256.Signing.PrivateKey(rawRepresentation: privateKeyData) // Przykład, wymaga konwersji z SecKey na Data }
Wybór miejsca przechowywania zależy od:
- Rozmiaru danych (mała objętość vs dane strukturalne).
- Typu danych (hasło vs plik vs klucz kryptograficzny).
- Wymaganego poziomu ochrony.
- Potrzeby synchronizacji między urządzeniami (Keychain).
- Potrzeby uwierzytelniania użytkownika do dostępu (Secure Enclave, File Protection).