Mobile Applications and Security Considerations

Mobile developers should always have the assumption that their applications can be hacked. That could include reverse engineering of the source code or data exfiltration. To this end is also the fact that the device in which the mobile application is run, in most cases cannot be trusted. Thus, a mobile developer should assume that a security breach of the device has either already happened, or will happen. Given this assumption, a mobile developer should be wary of the data and the way sensitive functionalities are implemented within the mobile application. It is crucial to not only maximize the application security but also minimize the damage by the application. Both iOS and Android provide mechanisms that can facilitate security. Support for these does vary depending on the utilized iOS and Android versions. Going through them all would be lengthy, so instead, this blog post aims to shed some high-level light on some of the best security practices when developing mobile applications. Interested readers are encouraged to dive into the more technical details, to get a more thorough understanding of the iOS and Android-provided security mechanisms.

Mobile Application projects, should like every other software development project, consider security at the offset. Starting of these considerations can effectively be done via a threat model. Not only, should it help determine what kind of attacks the mobile application may be vulnerable to but also how these potential attacks can be prevented. Developers can then use the threat model to guide their implementation of relevant preventive security controls. Designing the mobile application, or any application for that matter, based on a threat model can tremendously improve its security. For threat modeling in the context of mobile applications, consulting the "OWASP Mobile Application Security Verification Standards (MASVS)"[1] and "OWASP Mobile Top 10"[2] can help. The threat model will of course differ based on the sensitivity of the mobile application. However, there are some security best practices that can be followed for all mobile applications. These best practices can be divided into 8 sections. “General Configuration”, "Code Quality", "Data Storage", "Cryptography", "Network Configuration", "Authentication and Authorization", "App Resiliency" and "Penetration Testing".

General Configurations

When developing a mobile application, a common consideration is often what minimum iOS / Android version to target. From a security viewpoint, it is clear, that always try to use and target the latest iOS and Android versions. However, sometimes this is not practical due to user expectations or business requirements. Thus, when supporting lower versions, it is important to be aware of the security implications that pertain to specific versions. Considering this during threat modeling is important. For example, support for newer strong security mechanisms may not be available or certain vulnerabilities affect older versions. Take for example the Strandhogg and StrandHogg 2.0 vulnerabilities that affect Android version 9.0 or earlier. Enabling attackers to trick users into thinking that they are interacting with a legitimate application when they in fact are interacting with an attacker-controlled application.

It is important to properly sign mobile applications to serve as a verifiable mark. It identifies the application's author and ensures that the app has not been modified since its initial distribution. Also ensure the use of memory protection techniques such as “Address Space Layout Randomization (ASLR)”, “Position Independent Executable (PIE)”, and “Data Execution Prevention (DEP)”. These are automatically applied in newer versions of iOS and Android. However, supporting older versions may need manual activation of these features. In addition, mobile applications often need certain permissions to function. Limiting and only requesting the bare minimum of permissions needed, is an important aspect of minimizing the possible attack surface while also considering the privacy of users.

Especially on Android, when exposing various functionality of the mobile application to other applications running on the same device, it is important to limit this exposure by not exporting critical activities, services, receivers, and content providers. In the case that such elements of the mobile application need to be exported use adequate intent-filters, protection levels, and permissions to limit the possible attack surface. In addition, make sure that any provided input passed during invocation of exported functionality has been properly validated and sanitized. Without validation, any input can potentially be sent to the mobile application, and it may enable an attacker or a malicious application to exploit the exposed functionality.

If the mobile application is dependent on a WebView for some of its functionality, make sure to disable JavaScript execution. In case, JavaScript execution is needed, only allow JavaScript and HTML which are loaded locally from within the application data directory or from trusted backend web services only. Most importantly,  users should not be able to specify from which sources to load contents from, to prevent various web attacks.

Both iOS and Android take a “snapshot” of the mobile application's main window when the user transitions the application to the background. Developers should remove any sensitive data from views before moving to the background, ensuring that no sensitive information displayed in the mobile application is not inadvertently disclosed in the snapshot. As this snapshot is stored locally on the device, an attacker with physical access to the device could potentially extract the snapshots and view the sensitive data.

Code Quality

When developing applications, it is crucial to use secure coding principles. For example, “Deny by default”. The default action should be to deny access. Should an attempt to perform a task be denied, the application is as secure as it was before the task started. Another example is “Least privilege”. A user should be given only those privileges that are necessary to complete a task. Finally, “Complete mediation” ensures that every attempt to access a sensitive window, not just the first, is validated.

It is important that all unused, irrelevant, and debugging code is removed before release into production. It not only improves runtime performance but reduces the attack surface. Also, avoid simple logic. Especially for functionality related to security mechanisms. While most security mechanisms should be enforced on the backend web service, it might sometimes still be necessary to track some security states locally. For example, consider a local authentication scheme, where only a certain number of PIN code tries are allowed before the user needs to authenticate towards the backend web service again. Tracking the tries in a simple variable can be easily manipulated. Essentially allowing the infinite enumeration of PINs. Instead, integrate techniques such as encryption or obfuscation that add complexity for an attacker.

Data Storage

Data storage is essential to many mobile applications. However, developers should avoid or limit the storage of any sensitive data. Additionally, data read from storage should always be validated and possibly sanitized. Disclosure of sensitive information can have several consequences. For example, the compromise of users. Thus, thorough consideration and identification of the type of information stored by the mobile application are essential. From that, it should be determined whether particular and potentially sensitive information really needs to be stored locally. Sensitive data, which needs to be stored, should be properly protected by the mobile application.

Several places can be used for data storage, depending on the needs of the user, developer, and mobile application. “UserDefaults”, “Keychain” on iOS, “SharedPreferences”, “DataStore”, or “Keystore” on Android are often used to locally store mobile application data. However, databases such as “SQLite” or “Realm” can also be used. Important to keep in mind is that UserDefaults, SharedPreferences, and DataStore, should not be used to store sensitive data. Likewise, information should not be stored in unencrypted SQLite or Realm databases. For that purpose, the Keychain and the KeyStore / EncryptedSharedPreferences should be utilized instead. UserDefaults, SharedPreferences, DataStore, vanilla SQLite, and Realm do not provide any secure layer, thus data can be easily read. Needless to say, with the utilization of encrypted databases is that the private key should not be hardcoded in the source code or allow for easy retrieval from unprotected resources such as UserDefaults, SharedPreferences, or DataStore. For sensitive data consider augmenting protections offered by the Keychain and Keystore with application-level encryption. Rely upon the user to enter a passphrase to authenticate within the application, and then use that passphrase to encrypt data before storing it into the Keychain or Keystore. Another method to reduce the storage of sensitive data includes “transmit and display”. That is, do not persist to memory, store only in RAM, and clear on mobile application close.

Note that on iOS the data stored in the Keychain is not automatically removed upon removal of the mobile application. Thus, to protect the data stored developers should wipe all Keychain data associated with the mobile application, upon the mobile application’s first launch after installation. Additionally, if the mobile application depends on user authentication, Keychain data should be wiped as part of user logout.

Cryptography

Some sensitive data often needs to be stored within the mobile application. When doing so, strong cryptography and the available security mechanisms should be utilized. Proper use of cryptography is even more important in a mobile environment, where attackers might have physical access to the user's device. Proper protection of keys used for cryptographic operations is crucial. Otherwise, the purpose of using cryptography to protect data becomes useless. Cryptographic actions and the keys themselves must remain in the “Trusted Execution Environment” (Keystore) on Android or “Secure Enclave” (Keychain) on iOS. When storing the key in the Keychain on iOS use the most restrictive protection class (as defined by the kSecAttrAccessible attribute) that still allows the mobile application to function properly. For example, use “kSecAttrAccessibleWhenUnlockedThisDeviceOnly”, which restricts the migration of the Keychain at the time of backups while being only present when the user unlocks the device. When storing the key in the Keystore on Android, use “setUserAuthenticationRequired(true)” when creating the “KeyGenParameterSpec” object. Most importantly only use cryptographic operations from standard cryptographic APIs for Android and iOS. These implement well-known algorithms that are widely regarded as secure. Also, make sure to use sufficient key lengths. Even the most secure encryption algorithm becomes vulnerable to brute-force attacks when that algorithm uses an insufficient key size.

Network Configurations

Nowadays, most mobile applications have a dependency on a backend web service, that delivers data to and from the application. As a result, network-based attacks, such as packet sniffing, and man-in-the-middle-attacks can be a problem. That means that an attacker can potentially capture, view, and modify traffic sent and received between the mobile application and the backend web service. Thus, utilization of HTTPS / TLS is crucial. Preferably the backend web service should enforce HTTPS / TLS and disallow any connections via HTTP. In addition, only TLSv1.2 and TLSv1.3 with strong encryption cipher suites should be supported. To protect the data served by the backend web service, all utilized API endpoints should disallow caching via the “Cache-Control: no-store” HTTP header. In that way, data will not be locally cached on the device.

As an additional security measure, leverage “App Transport Security” on iOS and “Network Security Configuration” on Android to ensure the use of HTTPS. Better yet, the mobile application should use SSL/TLS certificate pinning, where the certificate or public key is stored within the mobile application to verify that it is communicating with the legitimate backend web service. However, it should be noted that future backend server configuration changes, such as changing to another “Certificate Authority (CA)”, can render the application unable to connect to the backend web service without receiving a software update.

Authentication and Authorization

Most mobile applications often require authentication. More complex mobile applications may have multiple user roles. Each with its own specific privileges. For authorization follow the security principle of least privilege. Ensure that users only have the minimal level of privileges needed for the mobile application to function. Only run authorization checks of an authenticated user at the backend web service rather than on the mobile application. Most severe security issues in mobile applications primarily stem from “Broken Object Level Authorization (BOLA)” or “Insecure Direct Object References (IDOR)”. That is inadequate authorization verification. Thus, make sure to properly secure every exposed API endpoint used in the application with authorization checks. In addition, for public object ids, use hard-to-guess alphanumeric numbers instead of consecutive and easily guessable ID numbers. That makes it harder for an attacker to obtain or guess references to objects.

When local authentication is used. That is the user "unlocks" the mobile application by providing a valid PIN, password, or biometrics, to continue an existing session with the backend web service or to protect some sensitive functionality, it should always be enforced at the backend web service or based on a cryptographic primitive to prevent bypasses when no data is returned from the authentication process. Preferably the provided PIN, Password, or Biometric should be used to derive an encryption key that enables the decryption of data. In that way, it is difficult for an attacker to access data for without knowing/having the correct PIN, Password, or Biometrics.

App Resiliency

Developers should consider implementing measures that make it challenging to attack the mobile application. The more time-consuming it is to attack an application, the more the incentive to attack decreases. Thus, mobile developers should implement mechanisms that make the mobile application more resilient. A defense-in-depth approach should preferably be followed. Here multiple defensive mechanisms or security controls are utilized.

Use code obfuscation to make it harder for an attacker to reverse engineer the application. In addition. Implement device root/jailbreak detection and use “DeviceCheck” on iOS and “SafetyNet” on Android to assess device and app integrity. In case the integrity cannot be verified, be sure to respond properly by preventing the execution or restricting the functionalities of the mobile application. That could be alerting the user and asking for accepting liability. Preventing execution by gracefully terminating. Securely wipe any sensitive data stored on the device. Proper action is key since all default security layers built into the Android or iOS operating system are weakened on a jailbroken or rooted device.

Penetration Testing

Before the production release of a new mobile application or a new version with added functionality, a penetration test can preferably be used to help map out any existing security issues. While most security issues should have been mitigated in the development process, a penetration test can act as a final check before releasing the mobile application into the wild. It can help minimize defect and remediation costs, as identifying vulnerabilities before production often cost less compared to removing them in a production system.

Conclusion

Security must be considered from the start of the mobile application development process. Threat modeling is relevant to use in determining the plausible threats associated with the application. From the threat model, security requirements can be defined, and appropriate measures implemented, to make the application as secure and resilient as possible. The goal should be to harden the mobile application, such that attacking it is not worth the effort and time.

 

[1] https://owasp.org/www-project-mobile-security-testing-guide/

[2] https://owasp.org/www-project-mobile-top-10/