How to use iOS Data Protection (updated for iOS 17)
This article was first published in October 2017 and was updated in September 2024.
Modern iOS devices support Data Protection, which secures user data using built-in encryption hardware. As of iOS 17, significant enhancements have been made, and understanding these updates is crucial for app developers. This post covers how apps can use iOS Data Protection to secure files, highlighting recent changes in the frameworks and file encryption methods.
Every file stored on an iOS device falls under one of four Data Protection classes, which dictate when the file can be read or written to. These protection types can be set using entitlements or programmatically, and it’s recommended to protect users’ data as securely as possible. From best to worst, these classes are:
-
NSFileProtectionComplete
— Files are only accessible when the device is unlocked. In iOS 17, improvements in this protection class ensure faster performance and enhanced encryption algorithms. This is the most secure option. -
NSFileProtectionCompleteUnlessOpen
— While the device is locked, files that are already open can still be accessed. This is useful for background tasks. -
NSFileProtectionCompleteUntilFirstUserAuthentication
— The file is accessible after the user enters their passcode once post-boot, even if the device is locked. -
NSFileProtectionNone
— Files can be accessed at any time. This option should be avoided unless absolutely necessary.
In iOS 17, file protection is now further streamlined through updated system APIs, providing better integration with background tasks, and improved performance when handling sensitive data during app lifecycle events. When trying to access a protected file outside its allowed conditions, the operation fails with a relevant error code, as before (NSFileReadNoPermissionError
, NSFileWriteNoPermissionError
).
Setting default protection levels
As of iOS 17, the process to configure Data Protection entitlements has remained largely the same, though improvements have been made in how provisioning profiles handle Data Protection settings. When setting default file protection, developers can define it in the entitlements file (com.apple.developer.default-data-protection
) or programmatically.
-
NSFileProtectionCompleteUntilFirstUserAuthentication — This remains the default since iOS 7.
-
NSFileProtectionComplete — You can set this as the default using Xcode’s Capabilities tab. However, developers should note that changing the entitlement post-installation has become more reliable in iOS 17, but it still doesn’t apply to existing files. Developers can now more easily manage Data Protection for shared containers programmatically due to improved APIs.
Programmatic file protection
To ensure full control over file protection, developers can programmatically set protection levels.
-
For single files
Use this for new files:
try data.write(to: fileURL, options: .completeFileProtection)
-
For directories
On iOS 17, when creating a new directory, files within that directory inherit the parent directory’s protection level. The FileManager
API can be used as before:
try FileManager.default.createDirectory(at: directoryURL, withIntermediateDirectories: true, attributes: [.protectionKey: FileProtectionType.complete])
-
iOS 17 update — Atomic writes
iOS 17 introduced new behavior with the .atomic
option when creating files. Now, files created with .atomic
inherit the protection level of the directory they’re created in, which addresses the issue present in earlier versions where files would inherit protection from the temporary directory instead of the target directory.
-
Managing file protection for existing files in a directory
When you set the protection level of a directory, it doesn’t automatically apply to existing files in that directory. You’ll need to update the protection level for each individual file. This can be done using FileManager.DirectoryEnumerator or NSDirectoryEnumerator:
guard let directoryEnumerator = FileManager.default.enumerator(at: directoryURL, includingPropertiesForKeys: [.fileProtectionKey], options: [], errorHandler: { url, error -> Bool in print(error) return true }) else { print("Could not create directory enumerator at \(directoryURL.path)") return } for case let fileURL as URL in directoryEnumerator { do { try fileURL.setResourceValue(URLFileProtection.complete, forKey: .fileProtectionKey) } catch { print("Failed to set protection level for file \(fileURL.path): \(error)") } }
Compliance and data privacy
As security and compliance requirements evolve, iOS 17 strengthens encryption methods in line with global data privacy regulations. Developers should always prioritize protecting user data, especially sensitive information, by using the most secure protection levels supported by iOS.
Conclusion
Data Protection on iOS 17 provides enhanced encryption methods and improved API performance, making it easier for developers to ensure user data remains private. The updated guidelines make iOS an even more secure platform for storing sensitive information. Implementing file protection in your apps is straightforward, but crucial, to stay compliant with modern security standards.
For further reading, see Apple’s latest platform security documentation.
Let me know if you think I’ve missed something.
FAQ
Here are a few frequently asked questions about iOS Data Protection.
What is iOS Data Protection?
iOS Data Protection is a feature that secures user data by using built-in encryption hardware, ensuring files are protected when a device is locked.
How many types of Data Protection are there in iOS?
There are four Data Protection types in iOS: NSFileProtectionComplete
, NSFileProtectionCompleteUnlessOpen
, NSFileProtectionCompleteUntilFirstUserAuthentication
, and NSFileProtectionNone
.
Can I change the protection level for existing files?
Yes, you can change the protection level for existing files programmatically using APIs like FileManager
or NSURL
.
Does Data Protection work in iOS Simulator?
No, Data Protection features do not function in iOS Simulator; testing should be conducted on actual devices.
How can I set a default protection level for my app?
You can set a default protection level in your app’s entitlements file in Xcode, specifically under the Data Protection capability.