NSFileProtectionComplete doesn't encrypt the core data file

前端 未结 4 1739
别那么骄傲
别那么骄傲 2020-12-03 12:36

I am using Xcode 7.3 for iOS 9.3 to try and encrypt a Core Data file. I am trying to use NSPersistentStoreFileProtectionKey and set it to NSFileProtectionComplete to enable

4条回答
  •  生来不讨喜
    2020-12-03 13:29

    Ok, I finally understand this.

    Using Xcode 7.3.1

    Enabling File Protection

    1. Enable File Protection using the Capabilities tab on your app target
    2. If you do not want the default NSFileProtectionComplete, change this setting in the developer portal under your app id
    3. Make sure Xcode has the new provisioning profile this creates.
    4. For protecting files your app creates, that's it.
    5. To protect Core Data, you need to add the NSPersistentStoreFileProtectionKey: NSFileProtectionComplete option to your persistent store.

    Example:

    var options: [NSObject : AnyObject] = [NSMigratePersistentStoresAutomaticallyOption: true,
                       NSPersistentStoreFileProtectionKey: NSFileProtectionComplete,
                    NSInferMappingModelAutomaticallyOption: true]
        do {
            try coordinator!.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: options)
    

    Testing File Protection

    I am not able to test this using a non-jailbroken device connected to a computer. Every attempt to access the device this way requires that I "trust" the computer and I believe that trusted computers are always able to read the phone's data ("Trusted computers can sync with your iOS device, create backups, and access your device's photos, videos, contacts, and other content" - https://support.apple.com/en-us/HT202778). I think the other answers on SO referencing this technique are no longer valid with more recent versions of iOS. Indeed, I am always able to download the container using XCode and view the app's data using iPhone Explorer. So how to test...

    1 - Create an archive and ensure that it is has the proper entitlements by running the following on the .app file from the command line:

    codesign -d --entitlements :- 
    

    You should see a key/value pair that represents your Data Protection level. In this example, NSFileProtectionComplete:

    com.apple.developer.default-data-protection
    NSFileProtectionComplete
    

    In addition, I used the following two techniques to satisfy myself that the data protection is indeed working. They both require code changes.

    2 - Add some code to verify that the proper NSFileProtectionKey is being set on your files and/or core data store:

    NSFileManager.defaultManager().attributesOfItemAtPath(dbPath.path!)
    

    If I print this out on one of my files I get:

    ["NSFileCreationDate": 2016-10-14 02:06:39 +0000, "NSFileGroupOwnerAccountName": mobile, "NSFileType": NSFileTypeRegular, "NSFileSystemNumber": 16777218, "NSFileOwnerAccountName": mobile, "NSFileReferenceCount": 1, "NSFileModificationDate": 2016-10-14 02:06:39 +0000, "NSFileExtensionHidden": 0, "NSFileSize": 81920, "NSFileGroupOwnerAccountID": 501, "NSFileOwnerAccountID": 501, "NSFilePosixPermissions": 420, "NSFileProtectionKey": NSFileProtectionComplete, "NSFileSystemFileNumber": 270902]

    Note the "NSFileProtectionKey": "NSFileProtectionComplete" pair.

    3 - Modify the following code and hook it up to some button in your app.

    @IBAction func settingButtonTouch(sender: AnyObject) {
            updateTimer = NSTimer.scheduledTimerWithTimeInterval(0.5, target: self,
                                                                 selector: #selector(TabbedOverviewViewController.runTest), userInfo: nil, repeats: true)
            registerBackgroundTask()
    }
    
    var backgroundTask: UIBackgroundTaskIdentifier = UIBackgroundTaskInvalid
    var updateTimer: NSTimer?
    
    func registerBackgroundTask() {
        backgroundTask = UIApplication.sharedApplication().beginBackgroundTaskWithExpirationHandler {
            [unowned self] in
            self.endBackgroundTask()
        }
        assert(backgroundTask != UIBackgroundTaskInvalid)
    }
    
    func endBackgroundTask() {
        NSLog("Background task ended.")
        UIApplication.sharedApplication().endBackgroundTask(backgroundTask)
        backgroundTask = UIBackgroundTaskInvalid
    }
    
    func runTest() {
        switch UIApplication.sharedApplication().applicationState {
        case .Active:
            NSLog("App is active.")
            checkFiles()
        case .Background:
            NSLog("App is backgrounded.")
            checkFiles()
        case .Inactive:
            break
        }
    }
    
    func checkFiles() {
        // attempt to access a protected resource, i.e. a core data store or file
    }        
    

    When you tap the button this code begins executing the checkFiles method every .5 seconds. This should run indefinitely with the app in the foreground or background - until you lock your phone. At that point it should reliably fail after roughly 10 seconds - exactly as described in the description of NSFileProtectionComplete.

提交回复
热议问题