Safe app best practices for better cyber security.

In the age of elevated and highly varied vectors for cyber security threats, maintaining good hygeine to protect your app users, is critical not only for the developer of an app, but also for consumer and app user safety.

Whilst the strategy and techniques chosen to protect app user safety will depend on what functionality the app provides users, the following practices should be front of mind for developers:

  1. Authentication
  2. Authorisation
  3. Data storage
  4. Anti-tampering and anti-reversing

Let's delve into each of the 4 areas.


Authentication

Validate user identity and ensure legitimate access. Examples include biometrics, personal identification numbers or multi-factor authentication code generators.

Implement Something-You-Know authentication as one of the MFA factors.

Something-You-Know represents a fundamental layer of identity verification involving information known only to the user, such as a PIN (Personal Identification Number), password, pattern, etc.

Implementing Something-You-Know as one of the MFA factors ensures a basic level of identity verification by requiring users to provide unique information associated with their accounts.

Implement Something-You-Have authentication as one of the MFA factors.

Something-You-Have requires users to authenticate with a physical device, app, or token that generates authentication credentials, which may include time-based One-Time Passwords (OTPs). Examples of such tokens include software tokens, hardware tokens, and SMS OTP.

Implementing Something-You-Have as one of the MFA factors adds complexity to the authentication process by requiring the possession of a tangible element, significantly reducing the likelihood of unauthorised access.

Developers should use a time-based OTP for software tokens, hardware tokens and SMS OTP. The following guidelines should be followed:

  • An OTP should only be valid for no longer than 30 seconds.
  • An incorrect input OTP after 3 attempts should be invalidated, and the user's session should be revoked or rejected.

Implement Something-You-Are authentication as one of the MFA factors.

Something-You-Are requires users to authenticate with biometric identifiers such as fingerprints, retina scans, or facial recognition.

Implementing Something-You-Are as one of the MFA factors adds a highly personalised and difficult-to-replicate authentication factor. It provides a more robust means of verifying user identity than the Something-You-Know and the Something-You-Have factors, reducing the risk of unauthorised access.

Developers should limit apps’ functionalities on devices lacking hardware Trusted Executed Environment (TEE) or biometrics (e.g. Android devices lacking TEE can be detected using the “isInsideSecureHardware” Android API.) and should invalidate biometric authentication if changes occur in the biometric mechanism, like enrolling a new fingerprint on the device. Both iOS and Android platforms support setting an app crypto key to expire in response to such changes.

Use context-based factors to authenticate.

Context-based factors introduce dynamic elements such as user location and device attributes. While MFA provides a robust layer of security by requiring multiple authentication factors, incorporating context-based factors creates a more comprehensive and adaptive authentication process that can offer additional benefits in addressing the evolving risks of unauthorised access.

Implementing context-based factors minimises the reliance on static credentials, making it more challenging for malicious actors to attempt unauthorised access. Developers should consider the following contextual factors to verify the identity of a user:

  • Geolocation: Allow access based on the real-world location of a device using GPS, Wi-Fi, or IP address geolocation.
  • Device Type: Allow access based on the characteristics of a device. e.g. screen size can determine if a device is a smartphone or tablet.

Implement secure session authentication.

Secure session authentication ensures robust session management for both stateful and stateless authentication. Poorly managed sessions, irrespective of whether the app follows stateful or stateless authentication methods, can lead to security threats such as unauthorised access, session hijacking, or data breaches.

Implementing secure session authentication for stateful sessions employs secure session identifiers, encrypted communication and proper timeouts to prevent unauthorised access. For stateless authentication, it ensures that tokens are tamper-resistant, maintaining authentication integrity without relying on server-side storage.

Implement secure stateful authentication.

Secure stateful authentication involves protecting and maintaining persistent sessions. While stateful authentication provides a seamless user experience through persistent user sessions, it can be vulnerable to various security threats, such as malicious actors attempting to steal session identifiers.

Implementing secure stateful authentication protects user accounts from unauthorised access and potential vulnerabilities associated with session management without compromising the balance between usability and security.

Developers should identify server-side endpoints that expose sensitive information or critical functionalities and adopt the following stateful session authentication best practices:

  • Reject requests with missing or invalid session IDs or tokens.
  • Generate Session IDs randomly on the server side without appending them to URLs.
  • Enhance Session ID security with proper length and entropy, making guessing difficult.
  • Exchange Session IDs only over secure HTTPS connections.
  • Avoid storing session IDs in persistent storage.
  • Verify session IDs for user access to privileged app elements.
  • Terminate sessions on the server side, deleting session information upon timeout or logout.

Implement secure stateless authentication.

Secure stateless authentication involves secure token practices for effective and scalable
authentication. While stateless authentication provides benefits, it can be more vulnerable to security threats such as user impersonation if tokens are not securely generated, transmitted and stored.

Implementing secure stateless authentication ensures that each authentication token is securely handled while reaping the benefits of efficiency and scalability, reducing the risk of unauthorised access. Developers should adopt the following stateless session authentication best practices:

  • Generate tokens on the server side without appending them to URLs.
  • Enhance token security with proper length and entropy, making guessing difficult.
  • Exchange tokens only over secure HTTPS connections.
  • Verify that no sensitive data, such as PII, is embedded in tokens.
  • Avoid storing tokens in persistent storage.
  • Verify tokens for user access to privileged app elements.
  • Terminate tokens on the server side, deleting token information upon timeout or logout.
  • Cryptographically sign tokens using a secure algorithm, avoiding the use of null algorithms.

Implement secure session termination during logout, inactivity, or app closure.

Secure session termination ensures the effective closure of user sessions. In scenarios such as logout, inactivity, or app closure scenarios, there is a potential for malicious actors to exploit any lingering access points if sessions are not appropriately managed.
Implementing secure session termination during logout, inactivity, or app closure can significantly reduce the risk of unauthorised access by automatically terminating user sessions and safeguarding user information from being accessed by unauthorised parties. Developers should:

  • reauthenticate users after logging out, app inactivity, idleness, backgrounding, absolute session timeouts, or abrupt/force closure.
  • generate new session identifiers on the server whenever users move up to a new authentication level to prevent session fixation.
  • ensure that session termination includes clearing or deauthorising all
    locally stored tokens or session identifiers.
  • determine the idle timeout value based on the risk and nature of the functionality.

Implement brute force protection for authentication.

Brute force attacks involve automated and systematic attempts to guess user credentials, for example, by trying various combinations of usernames and passwords to gain unauthorised access.

Brute force protection restricts the number of login attempts within a specified period. Implementing brute force protection for authentication can significantly mitigate the risk of unauthorised access, protect user accounts and maintain the integrity of the authentication process. Developers should implement brute force mechanisms through the following best practices:

  • Implement anti-automation checks.
  • Apply rate limiting for login attempts.
  • Incorporate progressive incremental time delays (e.g. 30 seconds, 1 minute, 2 minutes, 5 minutes) for login attempts.

Be mindful that all MFA mechanisms are vulnerable to brute force, and it is important to convey the reasons for the account lockout and provide accessible means for users to authenticate themselves and remove the lockout. Examples include calling a
helpline or utilising biometric verification.

Implement a transaction integrity verification mechanism.

While authentication ensures the user's identity, it does not eliminate the possibility of fraudulent activities during the transaction process. Transaction integrity verification mechanisms are auxiliary security functions that give users the time and tools to react to potential frauds. Implementing a transaction integrity verification mechanism ensures that each transaction undergoes thorough scrutiny to confirm its accuracy and authenticity.

Developers can implement the following suggested best practices:

  • Initiate a transaction verification/confirmation call.
  • Provide a real-time transaction history.
  • Implement a cooldown period of 12 hours to 24 hours.
  • Disable overseas transactions by default; enable only through MFA.

Authorisation

Define and validate user access rights to relevant resources within the app.

Implements server-side authorisation.

Server-side authorisation refers to validating and granting access permissions to users or apps by a server or an authorisation server. This ensures that access control decisions and permissions are managed and enforced server-side rather than client-side/by the device. By implementing server-side authorisation, developers reduce opportunities for malicious attackers to tamper or bypass security measures on the app to gain unauthorised access to sensitive data (i.e. PIIs and Authentication data).

Developers should implement server-side authorisation after successful authentication before granting access permissions and ensure that users are granted access based on the following:

  • Assigned role with permissions: Ensure that users can only perform tasks relevant to their responsibilities.
  • Contextual factors: Dynamic access scenarios such as Time of Access and Behavioural Analysis.

Implements client-side authorisation via device binding.

Client-side (i.e. on the device) authorisation is the process of managing access permissions within a mobile app. This is risky as relying on client-side authorisation can expose apps to vulnerabilities such as unauthorised access and potential fraud.

If an app’s business functions (e.g., instantiating software tokens) require client-side authorisations, device binding (a security practice that associates authorisations to access privileges on a particular device) is recommended. By implementing device binding, apps can verify device identity and establish trust. This reduces the risks associated with unauthorised access and maintains a secure, trusted path between devices, apps, and servers. Developers should establish binding between apps and the device when a user's identity is used for the first time on an unregistered mobile device and should also verify that apps:

  • Check for modifications to the device since the last runtime.
  • Check for modifications to the device identity markers.
  • Check that the device running the app is in a secure state (e.g. no jailbreaking or rooting).

The above are just some examples of best-practice techniques used by the industry. As the ecosystem of mobile devices evolves, these techniques may become out of date. As such, developers should keep abreast of the latest industry best practices to verify device bindings.

To verify an Android device, developers can:

  • Obtain unique identifiers like IMEI or Android ID.
  • Retrieve build information.
  • Leverage native OS API features, such as Google's SafetyNet.

To verify an iOS device, developers can:

  • Leverage native OS services, such as Apple's device ID, via UIDevice.

The app notifies users of all required permissions before they start using the app.

Required permissions are specific rights and capabilities that the app requests from the mobile device. These permissions define what resources or functionalities the app can access on users’ devices. Some examples include, but are not limited to, camera, microphone, location, etc.

By implementing proper notifications that inform the users of what permissions are being requested, developers can prevent users from unknowingly granting excessive permissions, which may allow malicious actors to exploit vulnerabilities and steal sensitive data (i.e. PIIs and Authentication Data). Such notifications will also allow users to make informed decisions about the apps they install.

Developers should:

  • use In-App (In-App) alerts to request users for access permission.
  • ensure that Notifications/Alerts do not display sensitive data.
  • only request essential permissions for the app’s functionality.

The app notifies users for all high-risk transactions that has been authorised and completed.

If an app has high-risk transaction functionalities, users should be notified immediately when a transaction has been authorised and completed. By implementing this control, developers can ensure that users are made aware immediately when high-risk transactions have been authorised and completed so that they may be able to identify
potential fraudulent transactions as soon as possible.

Developers should adopt the following methods to alert a user:

  • In-Application (In-App) alerts.
  • Email notifications.
  • Short Message Service (SMS) notifications.

Developers should also ensure that Notifications/Alerts do not display sensitive data and only request essential permissions for the app's functionality.

The above are just some examples of best-practice notification techniques used by the industry. As the ecosystem of mobile devices evolves, these techniques may become out of date. As such, developers should keep abreast of the latest industry best practices to notify users of high-risk transactions that are authorised and completed.


Data storage

Safeguard integrity and confidentiality of sensitive data in the user’s device and the app server.

The app stores sensitive data that is only necessary for transactions.

Sensitive data is defined as user data (PIIs) and authentication data (e.g., credentials, encryption keys, etc.). Developers should only store sensitive data that is necessary for app business functions. Accumulating unnecessary information increases the impact of potential security breaches, making an app an attractive target for malicious actors.

By implementing this security control, developers can ensure that exposure is limited to the data required for specific business functions, minimising the impact in the event of unauthorised access or data breaches.

Developers should classify data being used by the app based on an organisation’s sensitivity levels and based on legal law requirements and adopt the following guidelines to secure data that are classified as sensitive:

  1. Implement a secure storage solution based on its sensitivity on the client-side/server-side.
  2. Apply data protection measures (e.g. tokenising, hashing with salt, encrypting)
  3. Delete sensitive data when no longer necessary.

The app implements secure storage of sensitive data.

Secure storage for mobile apps refers to implementing techniques and practices to protect sensitive data stored on mobile devices and app servers from unauthorised access, theft or tampering. This involves best practices such as encryption, hashing, tokenisation, and proper access controls. By implementing secure storage, developers can mitigate against unauthorised access, device compromise, potential data breaches and data leaks.

Developers should implement a secure storage solution that is commensurate with the sensitivity of data and should also prioritise the following order for a secure storage solution (from the most sensitive data to the least sensitive data):

  1. Server-side (all sensitive data should be stored, server-side).
  2. Client-side within the Trusted Execution Environment (in the case where server-side is not possible, store all sensitive data in the client-side TEE).

The app stores sensitive data securely server-side.

Storing sensitive data server-side refers to storing data on remote app servers or databases. Such an approach creates a better environment to protect data from unauthorised access or breaches, enabling more secured access control, options to implement better security measures such as more complex encryptions and provisions of quicker security updates.

By implementing server-side storage of sensitive data, developers can mitigate against the inherent risks of client-side data storage, as client-side storage is inherently more susceptible to data storage exploitation techniques commonly used by malicious actors in mobile scams.

Developers should apply at least 1 of the following data protection measures:

  1. For passwords only, developers can use hashing with salt (hashing with salt is used to add an extra layer of security by making it computationally intensive for attackers
    to decipher original sensitive data. In the context of password storage or key derivation, developers should utilise one-way key derivation functions or slow hash algorithms, such as PBKDF2, bcrypt, or script.). Instead of storing actual passwords, unique salts are generated and combined with passwords, creating salted hashes.
  2. Developers can encrypt sensitive data with encryption standards such as AES-128.
  3. Developers can implement tokenisation with self-managed tokenisation or a tokenisation service, replacing sensitive data with tokens where possible. In addition, developers should ensure tokenisation is of sufficient length and complexity (backed by secure cryptography) based on data sensitivity and business needs.

The above are just some examples of best practices used by the industry. As the ecosystem of mobile devices evolves, these best practices may become out of date. As such, developers should be abreast of the latest industry best practices to store sensitive data securely server-side.

The app stores sensitive data securely client-side in a Trusted Execution Environment (TEE).

The Trusted Execution Environment (TEE) is an isolated area within a mobile device’s hardware or processor architecture that provides a highly secure environment for storing sensitive data and executing sensitive or critical operations. It is designed to protect sensitive data, cryptographic keys and critical processes from unauthorised access or tampering. If an app’s business functions require sensitive client-side storage, storing it in the device’s TEE is recommended.

By implementing proper storage of sensitive data in the client-side TEE, developers can mitigate against threats originating from within a compromised device and from external malicious actors. Such storage can also mitigate against unauthorised access to user’s sensitive data on an app and prevent any encryption keys from being stolen.

Developers should store sensitive data securely client-side in a Trusted Execution Environment (TEE) such as Android's ARM's TrustZone and Apple's Secure Enclave. Developers should also store minimally the following list of sensitive data in a TEE:

  • Biometric identifiers.
  • Authentication tokens.
  • Cryptographic keys in a secure key management system such as Android Keystore, iOS Keychain.

The above are just some examples of what sensitive data developers should store in the TEE. As the ecosystem of mobile devices evolves, developers should exercise the freedom to store any data they deem necessary to be stored in the TEE.

For devices without hardware TEEs, developers may consider the usage of virtualised TEEs. Alternatively, developers can consider disabling the app or disabling high-risk transaction functions of the app, as the app is deemed insecure for high-risk transactions.

The app deletes sensitive data when no longer necessary.

Deleting sensitive data refers to the process of permanently removing or erasing confidential, private or sensitive data from storage devices, servers or databases. This process ensures that sensitive data is irrecoverably removed and cannot be accessed, retrieved, accidentally exposed, or reconstructed by unauthorised individuals or through data recovery methods.

By implementing this process, developers can minimise the window in which attackers can exploit vulnerabilities to steal sensitive data. Developers should use the following persistent storage security techniques:

  • Clear stored cookies on app termination or use in-memory cookie storage.
  • Remove all sensitive data on app uninstallation.
  • Manually remove all database files containing sensitive data (e.g., iOS WebView caches) from the file system when related business functions cease.

The above are just some examples of best practices used by the industry. As the ecosystem of mobile devices evolves, these techniques may become out of date. As such, developers should be abreast of the latest industry best practices to delete sensitive data when no longer necessary.


Anti-tampering and anti-reversing

Implement measures to prevent tampering or compromise of the app. Examples include anti-virus capabilities and protection against keyboard monitoring and spying.

The app is code signed with certificates from official app stores.

Apps are often spoofed by malicious actors and distributed via less strictly regulated channels. Signing an app with certificates provided by official app stores assures the mobile OS and users that the mobile app is from a verified source.

Implementing code signing helps operating systems determine whether to allow software to run or install based on the signatures or certificates used to sign the code. This helps prevent the installation and execution of potentially harmful apps. In addition, code signing also assists with integrity verification, as signatures will change if the app has been tampered with.

Developers should code-sign their apps with certificates. This section provides examples of how to do this via the two most popular platforms, iOS and Android. It can be done for Apple’s App Store by enrolling in the Apple Developer Programme and creating a
certificate signing request in the developer portal. Developers can register for the Apple Developer Programme and can reference the following developer guide for code signing under things to note. For Android, there are a variety of App stores. For Google’s Play Store, it can be done by configuring Play App Signing, which is a requirement for distribution through Google’s Play Store.

The app implements jailbreak or root detection.

Rooted and jailbroken devices are generally considered insecure. Rooted or jailbroken devices allow users to gain elevated privileges, enabling easier circumvention of security and OS limitations. Such elevated privileges can be unsafe for apps as these privileges allow malicious actors to potentially exploit vulnerabilities, steal credentials, take over user devices and execute fraudulent app transactions.

By implementing jailbreak or root detection, developers can prevent the abovementioned exploits from happening, protect apps’ intellectual property, ensure the stability of apps and prevent the bypass of in-app systems.

Android jailbreak or root detection:

  1. Check for superuser or SU binary.
  2. Detect root file system changes.
  3. Look for rooted apps.
  4. Check for custom recovery.
  5. Check for unsafe API usage.

iOS jailbreak or root detection:

  1. Detect the use of restricted APIs.
  2. Look for jailbreak tweaks like mods.
  3. Look for unofficial app stores, e.g., check for Cydia App Store signature.
  4. Look for kernel modifications.
  5. Check for the integrity of the critical file systems.
  6. Use 3rd-party libraries designed to detect device tampering.

The above are just some examples of best-practice checks used by the industry. As the ecosystem of mobile devices evolves, these checks may become out of date. As such, developers should be abreast of the latest industry best practices to implement jailbreak or root detection.

The app implements emulator detection.

Emulators are software used to test mobile apps by allowing a user to test a mobile app on a variety of mimicked mobile versions and devices. Although useful for testing, apps should not allow themselves to be mounted on emulators outside of the development environment.

By implementing emulation detection, developers can prevent malicious actors from running dynamic analysis, rooting, debugging, instrumentation, hooking, and fuzz testing on an emulated device they can control. In doing so, developers can prevent malicious actors from discovering vulnerabilities within the app for exploitation.

Developers should implement the following detection strategy to identify features for commonly used emulation solutions. Some recommendations of things to check for are:

  • Check battery usage.
  • Check timestamps and clocks.
  • Check multi-touch behaviours.
  • Check memory and performance analysis.
  • Perform network checks.
  • Check whether it is hardware-based.
  • Check what the OS is based on.
  • Check for device fingerprints.
  • Check build configurations.
  • Check for emulator services and apps.

The above are just some examples of best-practice checks used by the industry. As the ecosystem of mobile devices evolves, these checks may become out of date. As such, developers should be abreast of the latest industry best practices to implement emulator detection.

The app implements anti-malware detection.

Malware apps are increasingly used by malicious actors as a vector to compromise users’ mobile devices as such devices provide users with the convenience needed to perform day-to-day transactions. Malware apps primarily utilise sideloading features as a channel to get users to install malware on their devices.

By implementing anti-malware detection capabilities on an app at runtime, developers can prevent users from being exploited via malware exploiting app vulnerabilities and OS vulnerabilities, stealing credentials, taking over the device, and executing fraudulent transactions. Developers should implement anti-malware detection capabilities in their apps. This can be done in a variety of ways, but are not limited to:

  • Incorporate a Runtime-Application-Self-Protection (RASP) Software Development Kit (SDK) into their apps.
  • Utilise RASP SDKs to check and detect malware apps at runtime.
  • Check for and prevent overlays.
  • Prevent clickjacking.
  • Prevent app memory hooking.

The above are just some examples of best-practice checks used by the industry. As the ecosystem of mobile devices evolves, these checks may become out of date. As such, developers should be abreast of the latest industry best practices to implement anti-malware detection.

If any form of maliciousness is detected, developers should disable the app and provide the user with the necessary information on why the app has been disabled and urge the user to uninstall the malicious app(s) on their device. Alternatively, developers should warn the user and disable high-risk functions on the app until the user remediates the malicious app(s).

The app implements anti-hooking mechanisms.

Hooking refers to a technique used by attackers to intercept or modify the behaviour of a mobile app at runtime. This involves inserting or hooking into the execution flow of an app to either monitor its activities, alter its behaviour, inject malicious code or modify existing code functions to exploit vulnerabilities.

By implementing anti-hooking mechanisms on apps, developers can prevent the above attacks from happening and prevent unauthorised access, protect high-risk transaction operations, detect and prevent tampering and modification attempts, preserve intellectual property and maintain app reliability. Developers should implement the following example mechanisms to mitigate against hooking attacks:

  • Implement protections to block code injections.
  • Implement protections to prevent method hooking by preventing modifications to the app source code (both on the client and server).
  • Implement protections to prevent the execution of modified codes in your app.
  • Implement protections to prevent memory access and memory manipulation of your app.
  • Implement tamper-resistant algorithms or anti-tampering SDKs (commonly known as Runtime-Application-Self-Protection SDKs).
  • Check for insecure parameters such as obsolete APIs and parameters.

The above are just some examples of best-practice checks used by the industry. As the ecosystem of mobile devices evolves, these checks may become out of date. As such, developers should be abreast of the latest industry best practices to implement anti-hooking mechanisms.

The app implements overlay, remote viewing, and screenshot countermeasures.

Sensitive information can be captured or recorded without the user’s explicit consent when an app has screen recording, screenshot or overlay functionalities. For example:

  • Overlay attacks deceive users by creating a fake layer mimicking trusted apps, aiming to steal sensitive data.
  • Remote viewing attacks involve unauthorised access to a device's screen, allowing attackers to harvest sensitive data remotely.
  • Screenshot attacks occur when malicious actors capture a device's screen without the user's consent, extracting sensitive data.

Implementing overlay, remote viewing, and screenshot countermeasures can ensure that sensitive information remains secure, user privacy is upheld, and sensitive data is protected against inadvertent loss or misuse.

Developers should implement anti-tampering and anti-malware checks via RASP SDKs to prevent malicious apps from utilising overlays and remote viewing exploits.

For screenshots, developers can utilise the FLAG_SECURE flag for Android apps and similar flags for iOS to block out all screenshot capabilities when using the app. However, suppose business functions require screenshot capabilities (e.g. taking a screenshot of a completed bank transaction). In that case, the recommendation is to disable screenshot capabilities for screens or pages that include sensitive data (PII and Authentication Data). Developers can also consider masking input with sensitive data and sensor screens when the app is backgrounded.

Some examples of where to disable these screenshot capabilities include but are not limited to Log-in pages, Multi-Factor Authentication pages, Security Credentials, and PII changing pages, etc.

The app implements anti-keystroke capturing or anti-keylogger against third-party virtual keyboards on Android devices.

Keystroke capturing and keylogging are methods malicious actors utilise to monitor, log, and record the keys pressed on a keyboard without the user’s knowledge and consent. This allows logging and capturing of potentially sensitive data (i.e. PII and Authentication Data).

By implementing an in-app keyboard, developers can control where the logging data goes and mitigate against the risk of insecure third-party virtual keyboards acting as keyloggers to capture keystrokes.

Along with using in-app keyboards, developers should implement the following suggestions for inputs that require sensitive data (i.e. PII and Authentication Data): Disable autocorrect, autofill, autosuggestion, cut, copy, and paste for functions/or apps that contain sensitive data. Some examples of functions that should utilise in-app keyboards include but are not limited to logging in, entering an OTP, or other verification factors, etc.