Understanding iOS App Security Practices

26 June 2018

Maintaining security is top priority when developing any mobile application. As new technologies emerge in the market, they are accompanied by new vulnerabilities. In this article, we examine the main security concerns for iOS applications in 2018.

Understanding iOS App Security Practices

Safe Storage of Data

iOS is perhaps best-known for its security. Despite its popularity resting on this reputation, over the years several serious vulnerabilities have resulted in the loss of user data. With every leak, new measures are put in place, but for ultimate security it is recommended that only the most necessary data is saved.

Users’ personal information should only be stored on Keychain, and if it is necessary to use a database, such as Core Data or Realm, it must be encrypted. User data shouldn’t be available through Spotlight search.

It may be worth disabling web requests caching, as this content may be saved to the disk. Cached requests may be removed with one line:

Basic security practices for iOS applications

Server Connection

As of iOS 9, Apple has implemented strict requirements for secure network connections, including App Transport Security (ATS) rules, which require all requests to the internet to be made via HTTPS and encrypted with TLS 1.2 (with forward secrecy support). iOS adheres to these requirements by default, and so compliance may only need to be manually implemented from the server side.

Developers have also had the opportunity to specify parameters for all connections as well as for requests to specific domains. All of these are registered to the application’s Info.plist file. Here the main parameter is NSAllowsArbitraryloads, which by default disables all ATS rules. If it’s turned on, Apple will request a valid explanation for the action when conducting an app review for the App Store.

It might seem strange to have this flag, but in practice it’s used in conjunction with another function – NSAllowArbitraryLoadsInWebContent, disabling ATS only inside the WebView – to ensure that browser pages opened in the application meet all of Apple’s security requirements. As this setting is only available in i0S 10, to have web pages open on iOS 9 devices there must be the NSAllowsArbitraryLoads flag, which will be ignored if the NSAllowArbitraryLoadsInWebContent parameter is available.


Even with the use of a HTTPS connection, third parties are still able to view data when communicating with the server. The Man-in-the-Middle attack, for example, targets social networks by acting as the “middleman” between the application and the server.

One way to combat this is with the use of SSL-pinning. In practice, this means that an application recognizes the SSL-certificate of a server, which is used for a HTTPS connection, and refuses to accept any other certificate. If the server receives an unknown certificate (such as with Man-in-the-Middle attacks) the connection is immediately terminated.

SSL-pinning can be implemented in a number of ways, including storing the certificate file, hash, or public key within the application itself. If the Alamofire library is being used for network connections, the ServerTrustPolicyManager class supports all pinning options.

There is, however, a significant drawback in the use of a hash or certificate: Once the certificate expires, an application update is necessary to incorporate the new data, otherwise the function will no longer work. If a public key has been used there is no need to use a previous key pair to regenerate the server certificate, as the public key will remain the same.

Application Authorization

In most applications, access is authorized through the use of either a PIN, typically four digits, or a password (made up of letters, digits, and/or symbols), both of which are chosen by the user at registration. Obviously this code is not intended to be saved to either the user’s device or the server, but validation for the entered code must occur on the server.

This code validation is set in the form of a hash through the algorithm PBKDF2, which is still recommended as a password hashing algorithm. For this algorithm to work, it requires a salt: a set of random characters generated once during registration and used for all subsequent authorizations.

Ideally, it is only the salt that should be stored in the application database. However, since many applications now offer the ability to log in using other methods, such as fingerprint ID or facial recognition, that use biometric data, meaning that it is necessary to store both the pin-code itself and the resulting hash in Keychain.

For security, the number of attempts to enter the correct pin is limited, a restriction imposed on the server side. Once the maximum number of attempts has been reached, the data stored on the disk is deleted and the user is automatically logged out.

Once the server has authorized the request, a token is produced to make all subsequent requests to the server. Tokens only have a limited duration, and “fade” within a certain time, and once they have expired the user must enter their pin again in order to receive a new one. The request can occur from both the server (if no requests for the token have been made within ten to fifteen minutes) and the application (if it has been idle for long enough, approximately two minutes). Tokens aren’t stored between sessions, and so a new one must be received with each new application launch from the input of the pin code.

Touch ID and Face ID

Biometric authorization makes the login process much easier for the user, and is considered particularly secure: According to Apple statistics, the chance of a two fingerprints matching is 1 in 50,000, while the chance of facial ID making a mistake is in 1 in 1,000,000. The authorization calculations are performed in the Secure Enclave co-processor, which is completely isolated from the operating system (more details about the technology can be found here). The users’ biometric data is therefore inaccessible to the application developer, although there are still concerns that this security measure can be hacked.

For example, an attacker could identify the pin-code for the user’s device, add their own fingerprint to the authorization list, and be authorized to use the app without its specific code. To circumvent this problem, the operating system offers a hash called evaluatedPolicyDomainState, which identifies a particular set of fingerprints. This hash can be downloaded to the disk with the first successful in-app authorization, and for each subsequent authorization the current value can be checked against the saved one: If the data is changed, the Touch ID (or Face ID) access is disabled and the user must re-enter the pin code for the app to save the new hash value.

Jailbreak Check

Apple’s strict regulations for its iOS may be controversial, but the fact of the matter is that if a user decides to jailbreak their smartphone, they are foregoing most of Apple’s security features. Any installed app could potentially gain access to the user’s data.

Jailbreaking an iPhone is becoming less common, likely due to each new iOS version making it harder to accomplish. However, it’s still worthwhile to run a jailbreak check, particularly as detecting it can be difficult: the app may block access to certain features or even be forbidden to access at all.

There are different techniques for performing a jailbreak check, such as searching for the existence of a Cydia package on the device or checking if it’s possible to record outside of the app sandbox. These aren’t fool-proof methods for protecting an app from being used on a jailbreak device, but they do make it much more difficult.

Anti-Fraud System

If someone else were to gain full access of a user’s device or account, there should still be steps in place to prevent them from performing in-app operations. One way of doing this is to send information to the server during authorization about the device (such as ID number, model, and iOS version) so that if a user does lose access to their phone, it can be reported and the device blacklisted on the server.

If a user chooses to share geolocation data, this provides another layer of security: If operations on the application are performed from atypical locations, it is possible to suspend the service until the user confirms that they are the one using the device.

Every important setting or operation change should be confirmed with an SMS code, with a limited number of attempts to enter it correctly.

Data Entry

Data entry even within the application should still be subject to maximum security measures. It is recommended that the autocomplete function (UITextField autoCorrectionType characteristics) is disabled for most text fields. If it isn’t, the input data, which is often personal, will be indexed by the operating system and appear as options for autocomplete in other applications. Password text fields should also be masked and should not support the ability to copy and paste between other fields or applications.

In order to bypass the keyloggers that potentially exist on the device, the PIN-code submitted for authorization is performed not with the system keyboard but with the number buttons on the screen.

Other iOS Features

When the user interacts the application, the operating system takes a screenshot, which is then displayed in the list of minimized applications. This screenshot is stored on the device, and may contain sensitive data depending on the screen when the image was taken. There are a number of ways to maintain privacy, such as blurring the contents of the screen or putting a “shutter” on top of the moment when the application is booting up, but the main concern is that the contents of the screen on the screenshot cannot be viewed.

For important operations WebView is not recommended, as there are various vulnerabilities associated with the execution of Javascript code. However, in some service applications it’s not possible to skip or delete and web pages, and in these circumstances it’s best to use SSL-pinning with a set of trusted certificates from third-party sites, which the application can receive from the server.

Code Protection

Although it’s impossible to completely protect against reverse engineering, there are ways to complicate the process that will act as a deterrent. One example is to try and detect the debugger connected to the application when it starts up; if the debugger is found, the application crashes.

Debugging symbols should not be supplied with the application, and in the project’s compilation settings all the values recommended by Apple for the App Store should be displayed.

If the project is written in Objective-C, there are third-party tools for obscuring the code to make reverse engineering even more difficult. There is no need for this if the code is written in Swift, since the compiler itself obscures the code when in Release mode.


In most cases, a serious application is only part of a broader service, which, in addition to the mobile client, includes a server and a connection. To ensure full protection of the service, all components must comply with informational security requirements, but these are still not 100% guaranteed. An attack is always possible, and the points described above only reduce the risks. The only way to prevent a serious breach when developing applications is to remember the following principles: all application code is considered public, the safest location for data is on the server, and any protection should be as complex as possible.