I recently read through the March 2017 iOS Security Guide and made a few notes—it’s quite dense! I thought I would share these notes so other people can benefit from the time I put in, too. Additions and clarifications from external sources where noted.
When new files are created on a device, they are automatically assigned a “Data Protection Class” that determines under what conditions the file may be read/written.
They are:
Available when unlocked (NSFileProtectionComplete). Access is only allowed when the device is unlocked.
Available on create and after open (NSFileProtectionCompleteUnlessOpen). This one is difficult to explain simply. Check out the docs for more info. If a file is created when the device is locked, the file can be accessed until it is closed. After the file is closed, you can’t open it again until unlock. If a file is opened when the device is unlocked, you can access the file even if the device is locked again.
Available after first unlock (NSFileProtectionCompleteUntilFirstUserAuthentication). This is the default data protection class for all third-party app files, unless otherwise specified.
Always available (NSFileProtectionNone). Not encrypted with a passcode, but the device UID it sounds like. So, you’re unable to read the files if you don’t have access to the device.
See Keychain Services Programming Guide.
The Keychain is implemented as a database stored on the file system. There is only one keychain database, and the securityd
daemon manages access.
On macOS, every new user is assigned a keychain called login.keychain
. On iOS, there is one keychain used by all applications.
A keychain item has data (i.e., the stuff you want to keep secret) and metadata about the item.
Keychain items can be synced with iCloud by setting the kSecAttrSynchronizable
attribute to kCFBooleanTrue
. Shared items may only be used by apps with the same TEAM_ID.
On iOS, encrypted keychain items by default are not available when the device is locked. This behavior can be changed by assigning a Keychain Protection Class to a keychain item.
Keychain access is determined by an app’s:
keychain-access-groups
(called ‘Keychain Groups’ in XCode under Project Settings > Capabilities > Keychain Sharing)application-identifier
, which is described in the Cocoa Core Competencies Docs and is TEAM_ID + BUNDLE_IDENTIFIER
application-group
Keychain items can’t be shared between applications made by different developers.
Similar to file encryption, keychain items are assigned a Keychain Protection Class
, which is:
Available when unlocked (kSecAttrAccessibleWhenUnlocked
). Access is only allowed when the device is unlocked.
Available after first unlock (kSecAttrAccessibleAfterFirstUnlock
). Just what it says.
Always available (kSecAttrAccessibleAlways
). Not encrypted with a passcode, but the device UID it sounds like. So, you’re unable to read the files if you don’t have access to the device.
Passcode enabled (kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
). The same as “Available when unlocked,” except that the item is only available on devices with a passcode. If the passcode is removed, items are deleted. Items are not migrated to a new device. Items are not synced to iCloud keychain. Items are not backed up. Items are not included in escrow keybags.
When accessing the keychain for background refresh services (e.g., on receipt of remote notifications), Apple recommends using kSecAttrAccessibleAfterFirstUnlock
.
iOS requires that apps are signed to ensure they haven’t been tampered with after they’ve left the developer’s hands. Stock apps (e.g., Safari) have been signed by Apple directly. Third-party apps (i.e., yours) have been signed by you with a certificate provided by Apple.
The system will do a runtime signature check of any frameworks used by a third-party app to verify their authenticity.
(What a dig from the iOS Security Guide: “Unlike other mobile platforms, iOS doesn’t allow users to install potentially malicious unsigned apps from websites, or run untrusted code.”)
At runtime, the operating system will also verify the signature of paged memory to make sure it hasn’t been modified since last run. Intense.
Every third-party app is sandboxed—it gets its own filesystem container and can’t touch the containers of other apps. A new sandbox is generated and randomly assigned at app install.
If the app needs to access resources provided by the system, it does so through APIs provided by Apple, not through direct access to the filesystem/processes. Access to these resources is controlled through Entitlements.
The OS uses Address Space Layout Randomization to reduce the likelihood of a successful buffer overflow attack.
By default, App Transport Security enforces the use of secure standards when communicating over the network. Apps must explicitly declare they wish to use insecure methods of communication.
App groups
Keybags
Effaceable Storage
Entitlements
Extensions
Core data, NSData, SQLite
Passcodes
Containers (filesystem/directory)
Device UID
How should I store sensitive information like passwords or API tokens?
The Security Guide recommends storing passwords in the keychain: “Many apps need to handle passwords and other short but sensitive bits of data, such as keys and login tokens. The iOS Keychain provides a secure way to store these items.”
What’s the point of the keychain?
They keychain allows you to: encrypt your secrets; allow/disallow access to secrets depending on the state of the device; and sync your secrets to iCloud by setting the kSecAttrSynchronizable
attribute.
The iOS Security Guide is quite technical and complicated. If I missed or misrepresented any of the information in the guide you think is important, please leave a comment below!
Category: Productivity
Tags: Engineering iOS