13 KiB
iOS Basics
Privilege Separation and Sandbox
Applications the user can access run as the mobile user while critical system processes run as root.
However, the sandbox allows better control over actions that processes and applications can perform.
For example, even if two processes run as the same user mobile
, they are not allowed to access or modify each other's data.
Each application is installed under private/var/mobile/Applications/{random ID}
Once installed, applications have limited read access to some system areas and functions SMS, phone call...
. If an application wants to access a protected area, a pop-up requesting permission appears.
Data Protection
App developers can leverage the iOS Data Protection APIs to implement fine-grained access control for user data stored in flash memory. The APIs are built on top of the Secure Enclave Processor SEP
. The SEP is a coprocessor that provides cryptographic operations for data protection and key management. A device-specific hardware key-the device UID (Unique ID)-is embedded in the secure enclave, ensuring the integrity of data protection even when the operating system kernel is compromised.
When a file is created on the disk, a new 256-bit AES key is generated with the help of secure enclave's hardware based random number generator. The content of the file is then encrypted with the generated key. And then, this key is saved encrypted with a class key along with the class ID, with both data encrypted by the system's key, inside the metadata of the file.
For decrypting the file, the metadata is decrypted using the system's key. Then using the class ID the class key is retrieved to decrypt the per-file key and decrypt the file.
Files can be assigned to one of four different protection classes, which are explained in more detail in the iOS Security Guide:
- Complete Protection (NSFileProtectionComplete): A key derived from the user passcode and the device UID protects this class key. The derived key is wiped from memory shortly after the device is locked, making the data inaccessible until the user unlocks the device.
- Protected Unless Open (NSFileProtectionCompleteUnlessOpen): This protection class is similar to Complete Protection, but, if the file is opened when unlocked, the app can continue to access the file even if the user locks the device. This protection class is used when, for example, a mail attachment is downloading in the background.
- Protected Until First User Authentication (NSFileProtectionCompleteUntilFirstUserAuthentication): The file can be accessed as soon as the user unlocks the device for the first time after booting. It can be accessed even if the user subsequently locks the device and the class key is not removed from memory.
- No Protection (NSFileProtectionNone): The key for this protection class is protected with the UID only. The class key is stored in "Effaceable Storage", which is a region of flash memory on the iOS device that allows the storage of small amounts of data. This protection class exists for fast remote wiping
immediate deletion of the class key, which makes the data inaccessible
.
All class keys except NSFileProtectionNone
are encrypted with a key derived from the device UID and the user's passcode. As a result, decryption can happen only on the device itself and requires the correct passcode.
Since iOS 7, the default data protection class is "Protected Until First User Authentication".
****FileDP is a program that you can upload and use inside the IPhone to inspect the data protection class of each file.
The Keychain
A keychain is an encrypted container where every application can store sensitive pieces of information and only the same app or authorised apps
can retrieve the contents.
The iOS generated its own password for the keychain and stores an encrypted version of this key in the device. This password is encrypted with AES using an AES key created by a PBKDF2 function of the user's passcode + salt the 256 bit device **UID** **only** **accessible** to the secure **enclave chipset** on the device
. Due to the use of this device UID as salt, a device won't be able to decrypt the keychain of a different device even knowing the users passcode.
Access to the Keychain is managed by the securityd
daemon, which grants access according to the app's Keychain-access-groups
, application-identifier
, and application-group
entitlements.
The Keychain API includes the following main operations:
SecItemAdd
SecItemUpdate
SecItemCopyMatching
SecItemDelete
The only ways to try to BF this password is dumping the encrypted key and BF the passcode + salt the **pbkdf2** function uses **at least 10000 iteration**s
. Or trying to BF inside the device to avoids BFing the salt, however, secure enclave ensures there is at least a 5s delay between 2 failed password attempts.
You can configure data protection for Keychain items by setting the kSecAttrAccessible
key in the call to SecItemAdd
or SecItemUpdate
.The following configurable accessibility values for kSecAttrAccessible are the Keychain Data Protection classes:
kSecAttrAccessibleAlways
: The data in the Keychain item can always be accessed, regardless of whether the device is locked.kSecAttrAccessibleAlwaysThisDeviceOnly
: The data in the Keychain item can always be accessed, regardless of whether the device is locked. The data won't be included in an iCloud or local backup.kSecAttrAccessibleAfterFirstUnlock
: The data in the Keychain item can't be accessed after a restart until the device has been unlocked once by the user.kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
: The data in the Keychain item can't be accessed after a restart until the device has been unlocked once by the user. Items with this attribute do not migrate to a new device. Thus, after restoring from a backup of a different device, these items will not be present.kSecAttrAccessibleWhenUnlocked
: The data in the Keychain item can be accessed only while the device is unlocked by the user.kSecAttrAccessibleWhenUnlockedThisDeviceOnly
: The data in the Keychain item can be accessed only while the device is unlocked by the user. The data won't be included in an iCloud or local backup.kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
: The data in the Keychain can be accessed only when the device is unlocked. This protection class is only available if a passcode is set on the device. The data won't be included in an iCloud or local backup.
AccessControlFlags
define the mechanisms with which users can authenticate the key `SecAccessControlCreateFlags`
:
kSecAccessControlDevicePasscode
: Access the item via a passcode.kSecAccessControlBiometryAny
: Access the item via one of the fingerprints registered to Touch ID. Adding or removing a fingerprint won't invalidate the item.kSecAccessControlBiometryCurrentSet
: Access the item via one of the fingerprints registered to Touch ID. Adding or removing a fingerprint will invalidate the item.kSecAccessControlUserPresence
: Access the item via either one of the registered fingerprintsusing Touch ID
or default to the passcode.
Please note that keys secured by Touch ID via `kSecAccessControlBiometryAny` or `kSecAccessControlBiometryCurrentSet`
are protected by the Secure Enclave: The Keychain holds a token only, not the actual key. The key resides in the Secure Enclave.
The iPhone uses the passcode introduced by the user unlocking the device to decrypt the secrets in the keychain.
iOS uses the AppIdentifierPrefix Team ID
and the BundleIdentifier provided by the dev
to enforce access control oven keychain items. Then, the same team can configure 2 apps to share keychain items.
When a backup process is initiated the keychain data backed up remains encrypted and the keychain password isn't included in the backup.
{% hint style="warning" %} In a jailbroken device the keychain isn't protected. {% endhint %}
Keychain Data Persistence
On iOS, when an application is uninstalled, the Keychain data used by the application is retained by the device, unlike the data stored by the application sandbox which is wiped. In the event that a user sells their device without performing a factory reset, the buyer of the device may be able to gain access to the previous user's application accounts and data by reinstalling the same applications used by the previous user. This would require no technical ability to perform.
There's no iOS API that developers can use to force wipe data when an application is uninstalled. Instead, developers should take the following steps to prevent Keychain data from persisting between application installations:
- When an application is first launched after installation, wipe all Keychain data associated with the application. This will prevent a device's second user from accidentally gaining access to the previous user's accounts. The following Swift example is a basic demonstration of this wiping procedure:
let userDefaults = UserDefaults.standard
if userDefaults.bool(forKey: "hasRunBefore") == false {
// Remove Keychain items here
// Update the flag indicator
userDefaults.set(true, forKey: "hasRunBefore")
userDefaults.synchronize() // Forces the app to update UserDefaults
}
- When developing logout functionality for an iOS application, make sure that the Keychain data is wiped as part of account logout. This will allow users to clear their accounts before uninstalling an application.
Objective-C and Swift Basics
Objecttive-C has a dynamic runtime, so when an Objective-C program is executed in iOS, it calls libraries whose address are resolved at runtime by comparing the name of the function sent in the message against a list of all the function names available.
At the beginning, only apps created by Apple run the iPhones, so they had access to everything as they were trusted. However, when Apple allowed third party applications, Apple just removed the headers files of the powerful functions to "hide" them to developers. However, developers found that "safe" functions needed a few of these undocumented functions and just creating a custom header file with the names of the undocumented functions, it was possible to invoke this powerful hidden functions. Actually, Apple, before allowing an app to be published, check if the app calls any of these prohibited functions.
Then, Swift appeared. As Swift is statically bound it doesn't resolve the address of the functions in runtime like Objective-C
, it can be checked more easily the calls a Swift program is going to make via static code analysis.
Device Management
From iOS version 6, there is built-in support for device management capability with fine grain controls that allows an organisation to control the corporate apple devices.
The enrolment can be initiated by the user installing an agent in order to access the corporate apps. In this case the device usually belongs to the user.
Or the company can indicate the serial numbers of the bought devices or the purchase order ID and specify the MDM profile to install on those devices. Note that Apple doesn't allow to enrol a particular device this way twice. Once the first profile is deleted the user needs to give consent to install another one.
The user can see the installed policies in Settings --> General --> Profile and Device Management
As these MDM policies are checking and limiting other applications, they are running with more privileges.
A MDM policy can enforce users to have a passcode set with a minimun password complexity.
The profiles are tied to the deviceID, signed and encrypted by the MDM server and tamper proof. They cannot be removed without losing all the corporate data.
MDM profiles allow to wipe all the data if there are X failed password attempts. Also, the admin can remote wipe the iPhone whenever via the MDM interface.
MDM agents will check also for possible jailbreaks of the device, as this is very dangerous state for an iPhone.