📜 ⬆️ ⬇️

Basic security practices for iOS applications



When developing any mobile application that processes user data, it is important to pay attention to security. This issue is particularly acute for applications where the full name, phone numbers, passports and other personal information appear. Our company has developed and continues to develop several projects of this kind, in particular applications for clients of Russian banks. Based on this experience, we have developed a set of security requirements that we follow. Naturally, every year there are new technologies and opportunities, and with them - new behaviors and vulnerabilities. In this article, we fixed the main points of security for iOS applications that are relevant at the beginning of 2018.

Data storage


iOS has always been famous for its security and attention to information security. Nevertheless, during the existence of this OS, several serious vulnerabilities were identified due to user data leaks. This once again reminds us that too many security measures do not exist and one cannot hope for everything in the system. The less information remains on the disk after using the application, the better.

Therefore, it is recommended to store only those data, without which it is impossible to do. If among them there is personal user information - it is stored exclusively in Keychain. If you need to use a full database, such as Core Data or Realm, it is necessarily encrypted.
')
Information available in a search through Spotlight should also not contain user data.

Do not forget about the fact that after interacting with the application on the disk will remain the data that the developer was not going to save specifically, for example, logs. Therefore, in the application to disk should not be logged either nothing, or only information in which personal data do not appear.

In addition, you can disable caching of web requests, because their contents are also saved to disk. You can do this as follows:

let cache = URLCache( memoryCapacity: 0, diskCapacity: 0, diskPath: nil) URLCache.shared = cache 

And you can delete already cached requests in one line:

 URLCache.shared.removeAllCachedResponses() 

Server connection


Before the release of iOS 9, applications could freely make requests to any address via HTTP. In this case, the data were transmitted over the network in an unencrypted form, and it was not difficult for attackers to track the contents of the request. Starting with iOS 9, Apple decided to impose strict network connection requirements and developed App Transport Security (ATS) rules, according to which all requests to the Internet should be made via the HTTPS protocol and encrypted using TLS 1.2 (with forward secrecy support). The operating system itself by default follows these requirements; therefore, it is only necessary to comply with them from the server side.

Developers also had the opportunity to specify connection parameters for all connections and for requests to specific domains. All of them are written in the file Info.plist application. Here the main parameter is NSAllowsArbitraryLoads, which disables all ATS rules (disabled by default). If you turn it on, then Apple, when conducting a review of the application in the App Store, will ask for a weighty rationale for this action. It may seem strange to have this flag, but in practice it is used in conjunction with another - NSAllowArbitraryLoadsInWebContent, which disables ATS only inside WebView. It is often necessary because we cannot guarantee that the browser pages in the application meet all Apple security requirements. This setting appeared only in iOS 10, so in order for web pages to open on devices with iOS 9, you have to turn on the NSAllowsArbitraryLoads flag. But for all subsequent iOS versions, the value of NSAllowsArbitraryLoads will be ignored if there is NSAllowArbitraryLoadsInWebContent.

SSL pinning


Even when using HTTPS connections, it remains possible for third parties to view data when communicating with the server. For example, in public networks, an attacker could monitor traffic using the Man-in-the-middle attack, in which he becomes an intermediary between the application and the server. You can fight this with SSL pinning. In practice, this means that the application knows the SSL server certificate used for the HTTPS connection, and it does not trust other certificates. When an unknown certificate is received from the server (as in the case of the Man-in-the-middle attack), the connection is terminated. Pinning can be done in different ways: the certificate file itself, its hash or public key can be stored in the application. If you use the Alamofire library for network connections, you can use the ServerTrustPolicyManager class, which supports all the pinning options.

It should be noted that the use of a hash or certificate has a significant drawback: when the certificate expires, you need to release an application update with new data, otherwise it will simply stop working. If you use the public key and regenerate the server certificate using the previous key pair, it will not be necessary to update the application, as the public key will remain the same.

Authorization in the application


In many applications, authorization occurs by entering a 4-6 digit PIN code, invented by the user during registration. Naturally, this code cannot be stored in its pure form either on the device or on the server.

Verification of the entered code for correctness should occur on the server, where it is sent as a hash obtained using the PBKDF2 algorithm (which is still recommended as a password hashing algorithm). For the operation of this algorithm, a salt is needed - a set of random characters that is generated once during registration and is used for all subsequent authorizations.

At best, only this salt should be stored in the application database. But in applications, it is often possible to log in using Touch ID and Face ID, when a user enters his account, providing only biometric data. In such situations, you have to store the PIN code itself or the hash resulting from it in Keychain.

The number of possible attempts to enter the pin-code is limited, and the restriction must be imposed on the server side. After using all attempts, the data stored on the disk is erased, and the user is automatically logged out.

After authorization on the server, we get a token, on which we make all subsequent requests to the server. The token has a limited period of validity and after some time it goes rotten. In this case, the user must enter the pin code again to get a new token. The action of the token can end both on the server (if no requests were made for this token within 10-15 minutes) or in the application (if it was minimized long enough, about 2 minutes).

The token is not stored between sessions, and with each new launch of the application, it must be obtained by entering a PIN code.

Touch ID and Face ID




Biometric authentication greatly simplifies entry into mobile applications. Apple cites statistics according to which the chance of a user's fingerprint coinciding with another person's fingerprint is 1 to 50,000, while the chance of face scans coinciding is 1 to 1,000,000. All related calculations are performed on the Secure Enclave coprocessor, which is completely isolated from the operating system (more about the technology can be found here ). Because of this, it is impossible to access or use the user's biometric data, so the application developer does not have to take care of this. However, there are some interesting points related to these technologies.

For example, an attacker could find out the PIN code from the phone itself, add its fingerprint to the list of prints known to the system, and log in using it in the application without knowing the PIN code. To solve this problem, the operating system provides a hash called evaluatedPolicyDomainState, which describes the current fingerprint set. This hash can be saved to disk during the first successful authorization in the application and during subsequent authorizations to check whether the current value differs from the saved one. If they are different, the fingerprint database has been changed, the Touch ID input is disabled, and the user must re-enter the application PIN code to save the new hash value. The same applies to Face ID.

Check for jailbreak


You can have different attitudes towards Apple’s policy of restricting user rights to control a smartphone, but the fact remains: if a user chooses to put Jailbreak on, most aspects of iOS security can be forgotten. Any installed application can potentially access all stored information.
Currently, Jailbreak has become less common, including due to the fact that with the release of each new version of iOS, it is becoming increasingly difficult.

When detecting a jailbreak, you can impose hard restrictions: block access to certain parts of the application or even prohibit its use.
You can check for Jailbreak in different ways. For example, check the availability of the Cydia package on the device or the ability to write outside the application's sandbox.

 func hasCydiaBundle() -> Bool { let filePath = "/Applications/Cydia.app" return FileManager.default.fileExists(atPath: filePath) } func writeOutSandbox() -> Bool { do { let filePath = "/private/test.txt" let fileContents = "test" try fileContents.write(toFile: filePath, atomically: true, encoding: .utf8) try? FileManager.default.removeItem(atPath: filePath) return true } catch { return false } } 

It is worth adding that such methods can not fully protect the application from being used on a device with a jailbreak, but this complicates it considerably.

Antifraud


Even if the attacker has received full access to the phone or user account, there must be ways to block his ability to perform operations in the application. To do this, during authorization, it is important to send information about the device to the server (ID, model, iOS version) - if the user has lost access to his phone, the device can be added to the black list on the server.

Also, when using the application, you can send data about the user's geolocation to the server (provided that he gave access to it). If operations are performed from atypical places, it is possible to suspend the service until the user confirms that the actions are actually being performed by him.

All important changes to the settings and operations must be confirmed using the SMS code. The number of attempts to enter the code should also be limited.

Data input


It is important to ensure security, including when entering information within the application.
For example, in most text fields it is recommended to disable the autocomplete feature (the UITextField autoCorrectionType property). If this is not done, the input data (which may be personal) will be indexed by the operating system and will appear as options for auto-completion in other applications. And all text fields in which passwords are entered are, of course, masked and do not support the ability to copy / paste.

To bypass the keyloggers that potentially exist on the device, the pin-code entry during authorization is not performed using the system keyboard, but using the number buttons on the screen.

Other iOS Features


When the user minimizes the application, the operating system takes a screenshot of the screen, which is then displayed in the list of minimized applications. This screenshot is stored in a folder on the smartphone, and it is important to provide an option in which the screenshot may contain personal data. This can be done in different ways: to block the screen contents or to put a “curtain” on top of it when the application is minimized, the main thing is that you cannot view the contents of the screen in the screenshot.

To perform important operations, it is not recommended to use WebView, in which various vulnerabilities related to the execution of Javascript code were previously found. However, in some service applications, web pages are indispensable. In such cases, it is also recommended to use SSL pinning with a set of trusted certificates from third-party sites that the application can receive from the server.

Code Security


It is completely impossible to protect oneself from reverse engineering, but there are ways to complicate this process. For example, when you start an application, you can try to detect a debugger connected to it.

 void disableDebugger() { void *dllHandle = dlopen(0, RTLD_GLOBAL | RTLD_NOW); ptrace_ptr_t ptrace_method_pointer = dlsym(dllHandle, "ptrace"); ptrace_method_pointer(PT_DENY_ATTACH, 0, 0, 0); dlclose(dllHandle); } static int __unused isDebuggerPresent(void) { int name[4]; struct kinfo_proc info; size_t infoSize = sizeof(info); info.kp_proc.p_flag = 0; name[0] = CTL_KERN; name[1] = KERN_PROC; name[2] = KERN_PROC_PID; name[3] = getpid(); if (sysctl(name, 4, &info, &infoSize, NULL, 0) == -1) { perror("sysctl failure"); exit(-1); } return ((info.kp_proc.p_flag & P_TRACED) != 0); } 

If the debugger is found, the application crashes.

The application also does not have to be supplied with debug symbols, and in the compilation settings of the project all the values ​​recommended by Apple for assemblies in the AppStore are set.

If the project is written in Objective-C, you can use third-party code obfuscation tools that further complicate reverse engineering. For Swift, there is no such need, since the compiler itself performs obfuscation when compiling in Release-mode.

Conclusion


A serious application in most cases is only part of some service, in which besides the mobile client there is a server and a connection with it. To ensure full protection of the service, all its components must comply with information security requirements. However, the security guarantee can never be one hundred percent. The possibility of an attack always exists, and all the points described above only reduce the risks or increase its value. Therefore, the only thing that can be done when developing applications is to adhere to the following principles: all application code is considered public, the best place for logic and data is on the server, and any protection should be comprehensive.

If you want to familiarize yourself with the topic of mobile application security, you should refer to the most popular resource on this topic: OWASP Mobile Security Project .
Also, Apple provides its own materials on this issue, for example, Security Development Checklist .

Source: https://habr.com/ru/post/349272/


All Articles