NSFileProtectionComplete不加密核心数据文件 [英] NSFileProtectionComplete doesn't encrypt the core data file

查看:907
本文介绍了NSFileProtectionComplete不加密核心数据文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用Xcode 7.3 for iOS 9.3来尝试加密Core Data文件。我试图使用NSPersistentStoreFileProtectionKey并将其设置为NSFileProtectionComplete启用加密。它不工作的某些原因,我可以总是看到由应用程序生成的.sqlite文件,浏览通过sqlitebrowser或iexplorer的内容。这是我的代码:

  lazy var persistentStoreCoordinator:NSPersistentStoreCoordinator = {
//应用程序的持久存储协调器。此实现创建并返回一个协调器,并向其添加了应用程序的存储。此属性是可选的,因为存在可能导致存储创建失败的合法错误条件。

//创建协调器和存储
let coordinator = NSPersistentStoreCoordinator(managedObjectModel:self.managedObjectModel)
let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent(SingleViewCoreData.sqlite)
var failureReason =创建或加载应用程序保存的数据时出错。


let dict:[NSObject:AnyObject] = [
NSPersistentStoreFileProtectionKey:NSFileProtectionComplete
]

do {
try coordinator .addPersistentStoreWithType(NSSQLiteStoreType,configuration:nil,URL:url,options:dict)
} catch {
//报告任何错误。
var dict = [String:AnyObject]()
dict [NSLocalizedDescriptionKey] =无法初始化应用程序保存的数据
dict [NSLocalizedFailureReasonErrorKey] = failureReason

dict [NSUnderlyingErrorKey] = error as NSError
let wrappedError = NSError(domain:YOUR_ERROR_DOMAIN,代码:9999,userInfo:dict)
//用代码替换以正确处理错误。
// abort()导致应用程序生成崩溃日志并终止。您不应在运送应用程序中使用此功能,但在开发过程中可能很有用。
NSLog(未解析的错误\(wrappedError),\(wrappedError.userInfo))
abort()
}

do {
let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent(SingleViewCoreData.sqlite)
try NSFileManager.defaultManager()。setAttributes([NSFileProtectionKey:NSFileProtectionComplete],ofItemAtPath:url.path!)

} catch {

}

do {
let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent(SingleViewCoreData.sqlite-wal)
try NSFileManager.defaultManager ().setAttributes([NSFileProtectionKey:NSFileProtectionComplete],ofItemAtPath:url.path!)
// try print(NSFileManager.defaultManager()。attributesOfFileSystemForPath(String(url)))

} catch {

}

do {
let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent(SingleViewCoreData.sqlite-shm)
try NSFileManager.defaultManager ().setAttributes([NSFileProtectionKey:NSFileProtectionComplete],ofItemAtPath:url.path!)
// try print(NSFileManager.defaultManager()。attributesOfFileSystemForPath(String(url)))

} catch {

}


return coordinator
}()

我还在功能中为我的目标启用了Data Protection。我已经从苹果开发者门户重新生成配置文件,并使用启用数据保护。



我也使用下面的代码来检查.sqlite的文件属性,.sqlite-wal和.sqlite-shm文件。 NSFileProtectionKey已正确设置其中所有3。

  func checkProtectionForLocalDb(atDir:String){

let fileManager = NSFileManager.defaultManager $ b let enumerator:NSDirectoryEnumerator = fileManager.enumeratorAtPath(atDir)!


在枚举器中的路径{

let attr:NSDictionary = enumerator.fileAttributes!
print(attr)


}


}

我也试过禁用日志模式,以防止-wal和-shm文件被创建。但我仍然可以阅读.sqlite文件。即使属性读取了NSFileProtectionComplete。



如Apple文档中所述, Apple文档检查变量protectedDataAvailable的值是否发生变化,如下面的代码所示

  public func applicationDidEnterBackground(application:UIApplication){
//使用此方法释放共享资源,保存用户数据,使计时器无效,并存储足够的应用程序状态信息以将应用程序恢复到其当前状态,以防日后终止。
//如果您的应用程序支持后台执行,则调用此方法,而不是applicationWillTerminate:当用户退出时。
NSThread.sleepForTimeInterval(10)
sleep(10)
let dataAvailable:Bool = UIApplication.sharedApplication()。protectedDataAvailable
print(Protected Data Available:+ String ))

}



如果我在没有延迟的情况下检查值到true,但在添加延迟后,它设置为false。这是一个令人鼓舞的,但是,当我下载容器,显示内容,它仍然有.sqlite文件,仍然显示的内容,当打开在sqlitebrowser。

解决方案

好的,我终于明白了这一点。



使用Xcode 7.3.1 ..



启用文件保护


  1. 使用应用目标

  2. 如果您不想使用默认的NSFileProtectionComplete,请在开发者平台中的应用ID下更改此设置

  3. 确保XCode具有新的供应配置文件

  4. 为了保护核心数据,您需要将NSPersistentStoreFileProtectionKey:NSFileProtectionComplete选项添加到您的应用程序所创建的文件中。

例如:

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


$ b



我无法使用连接到计算机的非越狱设备进行测试。每次尝试以此方式访问设备要求我信任计算机,我相信可信任的计算机总是能够读取手机的数据(受信任的计算机可以与您的iOS设备同步,创建备份,并访问您的设备的照片,视频,联系人和其他内容 - https://support.apple.com/en-us/HT202778 )。我认为其他答案在SO引用这种技术不再有效的更新版本的iOS。事实上,我始终能够使用XCode下载容器,并使用iPhone资源管理器查看应用程序的数据。那么如何测试...



1 - 通过运行以下语句创建归档文件并确保其具有正确的权利。 app file from the command line:

  codesign -d --entitlements: - < path_to_app_binary> 

您应该会看到代表数据保护级别的键/值对。在此示例中,NSFileProtectionComplete:

 < key> com.apple.developer.default-data-protection< / key> 
< string> NSFileProtectionComplete< / string>

此外,我使用以下两种技术来满足自己的数据保护确实工作。



2 - 添加一些代码以验证您的文件和/或核心数据存储上是否设置了正确的NSFileProtectionKey

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



如果我在我的一个文件上打印出来,我得到:

 < NSFileOwnerAccountName:mobile,NSFileReferenceCount:NSFileOwnerAccountName:NSFileOwnerAccountName:mobile,NSFileName NSFileOwnerAccountID:501,NSFileOwnerAccountID:501,NSFilePosixPermissions:420,NSFileOwnerAccountID:501,NSFileOwnerAccountID NSFileProtectionKey:NSFileProtectionKey:NSFileProtectionKey:NSFileProtectionKey:NSFileProtectionKey:NSFileProtectionKeyNSFileProtectionKey:NSFileProtectionComplete,NSFileSystemFileNumber:270902] 


$ b。



3 - 修改以下代码并将其挂接到您应用中的某个按钮。

  @IBAction func settingButtonTouch(sender:AnyObject){
updateTimer = NSTimer.scheduledTimerWithTimeInterval(0.5,target:self,
selector:#selector(TabbedOverviewViewController。
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(后台任务已结束)
UIApplication.sharedApplication ).endBackgroundTask(backgroundTask)
backgroundTask = UIBackgroundTaskInvalid
}

func runTest(){
switch UIApplication.sharedApplication()。applicationState {
case。活动:
NSLog(App is active。)
checkFiles()
case .Background:
NSLog(App is backgrounded。)
checkFiles
case .Inactive:
break
}
}

func checkFiles(){
//尝试访问受保护的资源,即核心数据存储或文件
}

点击按钮时,此代码开始执行checkFiles方法每隔0.5秒。这应该与应用程序在前台或后台无限期运行 - 直到你锁定你的手机。在这一点上,它应该可靠地失败大约10秒后 - 完全如描述NSFileProtectionComplete。


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 the encryption. It is not working for some reason and I can always see the .sqlite file generated by the app and browse through the content in sqlitebrowser or iexplorer. Here is my code :

lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = {
    // The persistent store coordinator for the application. This implementation creates and returns a coordinator, having added the store for the application to it. This property is optional since there are legitimate error conditions that could cause the creation of the store to fail.

    // Create the coordinator and store
    let coordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
    let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent("SingleViewCoreData.sqlite")
    var failureReason = "There was an error creating or loading the application's saved data."


    let dict: [NSObject : AnyObject] = [
        NSPersistentStoreFileProtectionKey        : NSFileProtectionComplete
    ]

    do {
        try coordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: dict)
    } catch {
        // Report any error we got.
        var dict = [String: AnyObject]()
        dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data"
        dict[NSLocalizedFailureReasonErrorKey] = failureReason

        dict[NSUnderlyingErrorKey] = error as NSError
        let wrappedError = NSError(domain: "YOUR_ERROR_DOMAIN", code: 9999, userInfo: dict)
        // Replace this with code to handle the error appropriately.
        // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
        NSLog("Unresolved error \(wrappedError), \(wrappedError.userInfo)")
        abort()
    }

    do {
        let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent("SingleViewCoreData.sqlite")
        try NSFileManager.defaultManager().setAttributes([NSFileProtectionKey : NSFileProtectionComplete], ofItemAtPath: url.path!)

    } catch {

    }

    do {
        let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent("SingleViewCoreData.sqlite-wal")
        try NSFileManager.defaultManager().setAttributes([NSFileProtectionKey : NSFileProtectionComplete], ofItemAtPath: url.path!)
        //            try print(NSFileManager.defaultManager().attributesOfFileSystemForPath(String(url)))

    } catch {

    }

    do {
        let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent("SingleViewCoreData.sqlite-shm")
        try NSFileManager.defaultManager().setAttributes([NSFileProtectionKey : NSFileProtectionComplete], ofItemAtPath: url.path!)
        //            try print(NSFileManager.defaultManager().attributesOfFileSystemForPath(String(url)))

    } catch {

    }


    return coordinator
}()

I have also enabled Data Protection for my target in the "Capabilities". I have regenerated the provisioning profile from the Apple Developer portal and am using that with Enabled Data Protection.

I am also using the following code to check the file attributes of .sqlite , .sqlite-wal and .sqlite-shm files. NSFileProtectionKey is correctly set for all 3 of them.

func checkProtectionForLocalDb(atDir : String){

    let fileManager = NSFileManager.defaultManager()
    let enumerator: NSDirectoryEnumerator = fileManager.enumeratorAtPath(atDir)!


    for path in enumerator {

        let attr : NSDictionary = enumerator.fileAttributes!
        print(attr)


    }


}

I also tried disabling the Journal mode to prevent -wal and -shm files from being created. But I can still read the .sqlite file. Even though the attributes read NSFileProtectionComplete.

As described in the Apple Documentation at Apple Docs under "Protecting Data using On Disk Encryption", I tried to check whether the value of variable protectedDataAvailable changes as shown in the code below

public func applicationDidEnterBackground(application: UIApplication) {
    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
    NSThread.sleepForTimeInterval(10)
    sleep(10)
    let dataAvailable : Bool = UIApplication.sharedApplication().protectedDataAvailable
    print("Protected Data Available : " + String(dataAvailable))

}

If I check the value without the delay it's set to true but after adding the delay it's set to false. This is kind of encouraging, however, right after, when I download the container, to show the content, it still has .sqlite file that still shows the content when opened in sqlitebrowser.

解决方案

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 :- <path_to_app_binary>

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

<key>com.apple.developer.default-data-protection</key>
<string>NSFileProtectionComplete</string>

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.

这篇关于NSFileProtectionComplete不加密核心数据文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆