- Mobile apps live and operate in untrusted environments, yet they contain valuable data and everything they need to function is included within the app or easy to derive.
- The vast majority of mobile apps are very easy to compromise because a) they lack basic security features or b) security is implemented superficially and thus easy to bypass using freely available tools and basic reverse engineering techniques.
- In order to secure mobile apps, a multi-layered and comprehensive security defense is required generally consisting of the following, where each of the below protections complements and reinforces the others:
- Application Shielding/RASP: Protects against dynamic attacks, malicious debugging, tampering, emulation, etc.
- Code Obfuscation – Makes the code or application logic hard to understand
- Data Encryption Protects data stored in or used by the app, including data in the app sandbox, as well as in strings, preferences, and many other places where data is stored in the code.
- Secure Communication – Protects data in transit and to protect the app’s chain of trust
- Jailbreak/Rooting prevention – Protects apps from compromise of the environment in which the app runs.
- The vast majority of mobile app security solutions/tools require mobile app developers to perform a significant amount of manual development work or source code changes. These tools include: mobile SDKs, open source security libraries, specialized compilers or obfuscators or programming-language specific solutions.
- None of these security solutions fits into the ways in which mobile apps are built today, which is rapid, continuous and automated.
- In order to break this cycle of poor app security, mobile app security must be automated, rapid, continuous and iterative, as well as guaranteeable and auditable. In other words, mobile app security needs to evolve to fit the way developers build apps and not the other way around.
At my company, we often analyze mobile applications at the request of our customers (Fortune 500 companies) to help them assess their security weaknesses via black-box penetration testing. What our security researchers find is pretty disturbing. Nearly all the apps on which we perform security assessments can be compromised within 15 minutes due to a lack of basic security best practices.
It’s not that mobile app developers aren’t implementing any security measures — some are trying. But the state of mobile app security is still not strong, and you don’t have to take my word for it. The Verizon Mobile Security Index 2021 shows that 76% of respondents said they’d caved in to pressure and sacrificed mobile security in some way. And this lack of security is evident in the ease in which apps can be compromised.
We see the same basic deficiencies in each Android and iOS app that we test. We either find mobile app security to be missing altogether or implemented superficially (and thus easily bypassed). In either case, this leaves the apps vulnerable to compromise without much time or effort, using basic reverse engineering techniques and freely available open-source tools.
In this article I’ll discuss some of the most common security deficiencies we encounter and explain the potential risks to mobile consumers, app developers and brands.
Insufficient Encryption and Lack of Data Protection
One of the biggest issues we find is an overall lack of data encryption. Data encryption is one of the most important methods for protecting sensitive data stored in or used by the app or users. Common problems we find in our testing ranges from a failure to encrypt strings, resources, defaults, preferences and other sensitive data stored in the code. Or if encryption is used, we often find inconsistent or incomplete implementations, use of insecure or outdated algorithms, weak cipher suites, key derivation and signing, or hard coded values stored in the app. Any combination of these can leave sensitive data exposed or stored insecurely in the app, as well as making the app easier to compromise, tamper with, or modify maliciously.
Another area of concern is that most mobile apps do not sufficiently protect data in transit as it travels over a network. There are many ways in which a mobile session can be compromised, resulting in data leakage or theft. Basic mobile app security best practices, such as OWASP’s Mobile Top 10, call for protection of mobile sessions using strong encryption of data in transit, securing API communications, and ensuring the authenticity and validity of the digital chain of trust (CAs and digital certificates), just to name a few. We find the security model of most apps to be insufficient in those areas.
Sometimes the deficiencies take the form of poorly implemented APIs that expose more information than is necessary in API calls, or use of insecure transmission (SSL vs TLS). Other times we find applications fail to inspect certificates offered by a server, or that certificates can be easily forged, swapped or otherwise manipulated. In each case, the data is vulnerable as it traverses the network.
Failure to encrypt data end-to-end, or weaknesses in the encryption model expose apps to the following threats:
- Session hijacking or redirection to malicious proxies, endpoints, websites, or servers
- Data theft, credential theft, harvesting usernames/passwords
- Harvesting API keys to access sensitive servers, infiltrate the backend, or conduct credential stuffing attacks
- Man-in-the-middle (MitM) attacks, impersonation
- Phishing, malware delivery
Failure to Prevent Reverse Engineering and Tampering
The next major area of exposure is that most mobile apps lack strong app shielding and obfuscation – two of the most important ways to protect the app and source code against malicious reverse engineering and tampering.
Un-obfuscated code makes it easy for attackers to understand how an app works simply by reading the source code. They use this information to craft attacks against apps or to steal user data. Here are a few examples of attack scenarios of how this is done:
- Use disassemblers like Hopper, IDA-Pro, or Ghidra to analyze iOS code and modify an application’s values stored in memory.
- Search for strings in the source code of Android or iOS apps to locate sensitive user data stored unencrypted in strings.xml in Android apps or CFStrings, NSUserDefaults in iOS apps. Such practices can be used to steal/harvest data as well as to understand how data is shared or externalized with critical downstream systems.
- Analyze the Android manifest to understand the app’s permissions, intents, how the app shares data with other apps, or to learn about how the app is signed. This information helps cybercriminals create malware that abuses, mimics or impersonates common app or OS functionality. They can also create clones or fakes by abusing code signing methods.
- Analyze DEX files to locate, understand or compromise high-value application classes or workflows. In Android apps, DEX files are executable Java classes in the app’s control flow (logic). For example, hackers can analyze an app’s control flow to understand the business logic of a payment processing system by tracing method or function calls in the source code of an application class that handles in-app payments.
- Hackers routinely attach debuggers to apps for the purpose of understanding how the app executes certain functions, or to crash the app purposely at a specific point in order to analyze the crash dumps or stack traces.
Code obfuscation is one of the primary methods of preventing static code analysis. Obfuscation is the practice of obscuring source code and application logic to prevent attackers from understanding the meaning, intent or function of the source code, including how it executes instructions or logic. Obfuscation, coupled with app shielding, are considered two of the most important ‘first lines of defense’ against malicious reversing (both static and dynamic).
There are many techniques to obfuscate code, and a comprehensive solution requires implementing multiple techniques that complement and reinforce each other (so that the protections cannot be circumvented or bypassed).
A robust obfuscation solution requires protection of both native and non-native code and libraries, including string and resource encryption, encryption of app preferences and user defaults. In addition, it’s also important to obfuscate an application’s control flows and protect executable code (app logic, DEX files), including such diverse techniques as dummy code insertion, replacing function call targets, inserting arbitrary paths into the flow, or making the function tree appear broken to attackers by hiding the original code path in an encrypted location. And finally, it’s always recommended to strip debug information, so that hackers can’t sift through stack traces and easily understand the application’s behavior.
On the dynamic side, it’s important to protect against malicious debugging, tampering, emulators/simulators, other unwanted analysis or modification of an app while it runs.
Lack of Jailbreak/Rooting Prevention
Another area of weakness in mobile applications is a lack of protection from running in unsafe environments.
Hackers often run apps on jailbroken/rooted devices because doing so allows them to elevate admin privileges or modify low-level system files all of which are used to compromise the app or data or take control over the app or environment. Jailbreaking/rooting allows hackers to attack mobile apps more easily and do far more damage or use more powerful tools/features to compromise the app.
For instance, they can bypass or disable an application’s existing defense (for example, turn off anti-tampering or disable threat defense SDKs). Or they can modify signals going to or from the app, change the execution path of code, or even remove code or replace it with their own malicious implementation.
Advanced jailbreak and root hiding tools like Checkra1n (iOS) and Magisk (Android) are generally used to bypass detection techniques, hide the fact that the OS has been compromised, and elevate/manage root privileges for malware or other malicious apps.
It’s critical for mobile applications to have built-in protections against these techniques, methods and tools. And the protections should be implemented at multiple layers throughout the code and work in concert with other features in the app’s security model (so that they cannot be bypassed easily).
Lack of Protection Against Dynamic Instrumentation and Code Injection
Finally, at the top of the hacker food chain are very powerful dynamic instrumentation frameworks like Frida, which cybercriminals use to hook into apps, discover and attach to running processes, inject or modify an application’s code or memory during runtime, or change an app’s behavior using techniques such as function hooking or method swizzling.
Bad actors use these techniques for a plethora of malicious actions, such as account takeovers, compromising e-commerce sites, or infiltrating a mobile app’s backend using a combination of trojans, click-bots, RATs, botnets and other forms of malware which are designed to abuse legitimate app or OS functionality, masquerade as trusted apps or entities, and trick mobile users into performing harmful actions inadvertently.
Why Traditional Security Approaches Don’t Work In Mobile Apps
To achieve a multi-layered defense, the bare minimum security best practices are app shielding, anti-tampering, code obfuscation, data encryption (including strings, resources, preferences), jailbreak/rooting prevention, and man-in-the-middle prevention (such as certificate pinning or certificate validation). There are commercial SDKs and 3rd party libraries available to developers who wish to take a DIY approach. But fundamentally these approaches often require extensive development work and introduce additional frameworks or programming language dependencies and incompatibilities.
Allow me to make my point using encryption as an example. Let’s say you wanted to implement data encryption using 3rd party libraries or SDKs. There’s data structure dependencies: different data types have varying sensitivities to latency. Where you store the data will also constrain your choices on the encryption model you use. How often the data needs to be accessed and by what/whom/when the data needs to be available is also a challenge.
Then there’s the encryption model itself: which algorithm is right for your data? How do you validate the security requirements or performance characteristics of the algorithm for your diverse data types? Next there’s programming language dependencies: Android encryption libraries or SDKs for Java may not work for Kotlin. There’s the native C or C++ layer, which would require yet another implementation.
In iOS, same deal. You might visit StackOverflow and find that a common cryptokit for Swift won’t work for Objective C.
Finally, there’s key management. How do you derive the keys, what key strength should you use, and most importantly where do you store the encryption keys?
And I could go on for days. Not to mention, each of the above decisions can have a dramatic impact on the app’s performance, usability and security posture, the extent of which you’ll never know until you do the development!
And that’s just one security feature – encryption! To implement a multi-layered defense using SDKs or 3rd party libraries would require many SDKs (at least two or more to cover each of the categories I described above). Each SDK could be its own development project, requiring manual coding, specialized resources, trial and error development work. Each SDK would introduce its own framework and programming language dependencies, which may in fact conflict with one another.
So how can mobile developers solve this seemingly intractable problem? The answer lies in automating mobile app security.
The Problem: Traditional Mobile App Security Does Not Fit DevSecOps
While there are many reasons apps are not as secure as they should be, the root of the problem rests in the way in which mobile apps are developed, released, and updated in a modern agile organization.
The rifts between security and DevOps span across organizational cultures, workflows, toolsets and products. Simply put, Dev and Ops operate in a world where everything is dynamic, automated, agile, integrated, iterative, and continuous. The traditional world of mobile app security is the opposite – static (set and forget), manual (line by line coding), monolithic. You can’t take a laborious manual process (traditional security, SDK based approaches) and try to cobble together a multi-layered, comprehensive defense framework by framework, line by line, SDK by SDK, plugin by plugin. A manual monolithic process will never fit into an agile delivery model no matter how to try to slice it.
The true promise of DevSecOps is about built-in Rapid Mobile App Security (RMAS), delivered as a fundamental part of an agile release process, where security is designed into the process at each and every phase of the life cycle, and where security features or the security model can be delivered and evolved atomically, iteratively and dynamically – in a way that fits the specific and unique characteristics of the app itself. In other words, the security model adapts to fit the app (not the other way around).
The way forward for mobile app security is automation, which is what made DevOps possible in the first place. By applying AI and ML, the industry can create automated security implementations that will truly enable DevSecOps, allowing developers, ops and security professionals to deliver secure apps on time within an agile, fast moving and iterative app lifecycle and release process! That’s what I call Security Release Management.
About the Author
Alan Bavosa is VP of security products at Appdome, where he helps customers identify and address security gaps in their Android and iOS apps. Prior to joining Appdome, Alan was VP of products at Palerra, a cloud security automation company acquired by Oracle, and global head of products at ArcSight, a SEIM and log management company that was later acquired by HP.