Mobile AppSec: Understanding Improper Mobile Platform Usage and Client Code Quality

Eric Goldman
Walmart Global Tech Blog
12 min readMay 25, 2021
Photo by Misael Moreno on Unsplash

Introduction

Modern mobile application development allows developers to provide a rich and responsive experience to users. When using operating systems like Android and iOS, access to hardware and services is streamlined and fairly standardized. This makes it easy to rapidly develop applications which reliably use features like handing off tasks/data to other applications and services.

While the platform SDKs for such features are well documented, there are certain security trade-offs all developers must understand and certain patterns to avoid. What is easy (or easily found on Google / StackOverflow), isn’t always robust or secure. At the same time, the same secure coding concepts that apply to web and other frameworks still apply to both the client-side and server-side portions of your mobile application.

When developing mobile apps, you should be aware of built-in libraries and features that can provide the functionality required instead of relying on custom built code, or unnecessary third-party libraries. Furthermore, some convenient and recommended practices should be avoided to ensure that your code is secure and you maintain privacy. Not all defaults and popular patterns are the best or most secure choice.

Understanding the Risk

Mobile apps often interact with various hardware, system services, and other applications. You should use such capabilities careful and only when absolutely necessary to reduce the ability for misuse.

For example, any permission that you request for your app is permission that could then be used by an attacker if they find a flaw or vulnerability in your app. Remember that any app binary can be reverse engineered; attackers always have the ability to learn your client-side application’s innerworkings.

You must always remember that unlike a web application, which operates in a much more restricted sandbox, your mobile application may have full operating system and file system access. This introduces some additional considerations when coding and designing your app.

System Features

Let’s start by thinking about some concerns related to user generated images. For example, you are working on an mobile application with a screen that provides detailed personal and financial data…

  • When your app goes to the background, typically a screenshot is cached for when the user wants to switch back / between apps.
  • In addition, a user may take a screenshot at any time which is stored in the main image storage location on the OS by default, which is accessible to other apps, sync services, etc.

However, there are techniques to address screenshotting within your application and to sanitize screenshots for backgrounding / app switching (set allowScreenShot = false if using MDM). In addition, when your app creates or stores images, you should determine whether you want to restrict access to the app’s sandbox or allow any other app to read the application. Learn more about such functionality on iOS in the iOS Developer Docs.

Inter-Application Data Sharing

Another area where risk may be introduced is through inter-application data sharing. For example, the intents functionality in Android allows you to request another application handle some activity or process. Your app may handle intents or may send intents. When handling intents, the data must not be implicitly trusted, as the sending app may be malicious or may be vulnerable to exploit. When making requests to other apps, you should always try to use explicit intents, as opposed to implicit intents; otherwise, you cannot be sure what service will process the intent and what they may do with the data.

Don’t Know? Don’t need? Don’t Use!

In general, misusing a platform feature, or not properly understanding the risks and defaults of platform features, can open your application up to misuse and data leakage. Further, you must never trust any data/input implicitly from users, the file system, or other applications. There are no built-in guarantees and systems are not always designed with security-first configurations. Just like on a web application, you must ensure that you follow proactive and preemptive secure coding practices.

Defense Overview

Defending your mobile app requires an ongoing commitment to security. Mobile operating systems evolve very quickly. You must determine for how long you want to support legacy and outdated hardware, which may not be able to utilize more modern and secure functionality: There is a trade-off between being compatible with as many users as possible and requiring usage of legacy and insecure APIs and processes. At the same time, as new features become available and you learn more secure patterns, you must stay up to date and evolve your application. Before using any new feature, or when revisiting old code, be sure to review the current platform documentation for the features used in your app.

Here are some general principles to remember:

  • Don’t use a functionality unless it is really necessary and satisfies a needed business requirement
  • Minimize any permissions and follow secure coding practices whenever you process input
  • Minimize data and processing on the client-side that is sensitive or risky; you are always more in control on your own server
  • Be aware of where your app exports/saves data, logs, and any other output — think about where and when that data may be accessible to other apps, in sync, in backups, etc.
  • Using non-native code or WebViews requires understanding of mobile security concerns, OS level security, as well as web-app security concerns

A Note on Client Code Quality

Traditional application security concepts and web security concepts are still important on mobile applications.

Watch out for the following:

  • If your app relies on a local or remote database, SQL injection is still possible, and your local SQLite database is likely not secure enough for confidential / sensitive / high-risk data
  • If your app is non-native or uses WebViews, cross-site scripting (XSS) is still a concern and may impact other parts of your app
  • If you use outdated third-party libraries or third-party libraries with known vulnerabilities, your app will also be vulnerable

Follow good secure coding practices:

  • Minimize access to data and functions available to the user and available client-side
  • Fail securely and anticipate that that your app will receive bad input, intents, files, etc.
  • Practice good release management and ensure proper separation between production and non-production environments and configs
  • Keep all dependencies up to date and remove unnecessary and extraneous functionality — sometimes you need to rewrite a module yourself or strip out functionality

Improper Platform Usage Security Demo

Demo App Overview

To demonstrate the impact of how hackers can abuse platform features to leverage flaws in an app, we created a purposefully vulnerable application called DeepLinkXSSDemo. The application is very simple and minimal:

  • It registers a URL handler for any link that starts with “http://example.com/hello”
  • It expects a URL in the format of “http://example.com/hello/[Name]” where [Name] is expected to be something like “John”, “Ratish”, or “Jan”
  • The name value is then parsed and appended to a URL used to launch a locally embedded HTML file in a WebView
  • The application then displays “Hello, [Name]” on the screen using the WebView

Demo — Code Walkthrough

Registering Intent in AndroidManifest.XML: In order to allow the app to intercept requests for URLS we must request the proper permissions in the manifest file, and then register the intent for our desired activity, which will be launched when the URL is encountered. See below, starting on line 27, that we are registering “http://example.com/hello” in the LoadDeepLink activity indicated on line 20 in AndroidManifest.xml.

Manifest Showing Deep Link Intent Handler (AndroidManifest.xml)

Creating the WebView in the Activity Layout: Our app’s interface consists of simply declaring a WebView that we can reference later in our actual activity code. We specify the ID on line 10 in activity_deep_link.xml

Activity Layout Showing WebView (activity_deep_link.xml)

Activity Code to Wire Up the WebView: We instantiate the WebView by referencing the WebView (created in the above layout) on line 22 in our JAVA code below (LoadDeepLink.java). We then configure a few settings, the most important one for us is on line 26 of LoadDeepLink.java, where we enable JavaScript. Rather then doing the processing in JAVA/Kotlin, the developers of this app preferred to use their JavaScript skills and minimize the amount of native development.

Starting on line 31 of LoadDeepLink.java we handle the Intent which we registered in the manifest file above. Line 34 allows us to extract the last part of the URL that triggered the intent, which in our case should be the [Name] value.

Finally, on line 36 we take the [Name] value and append it as a URL/GET parameter to the local HTML file we will use to render the output in the WebView.

Activity Java Code (LoadDeepLink.java)

NOTE — Android Studio Warns us about bad ideas: You may have noticed in the above screenshot that line 26 of LoadDeepLink.java was highlighted, even though it was not the active line. When you mouse over this line (see screenshot below), Android Studio warns you that enabling JavaScript is dangerous… We will prove them right 😊

Detail of security issue when you mouseover “setJavaScriptEnabled(true)” in LoadDeepLink.java

HTML Code in our WebView: Now, let’s look at our HTML and JavaScript that will extract the [Name] value and display it as part of our app.

On line 3 of hello.html we declare a span with id showName and the initial value is set to “Friend”. The script tag starting on line 4 is used to obtain the URL/GET parameter passed in to the WebView from the intent in “LoadDeepLink.java” that we declared above (line 36 in that file).

Line 10 of hello.html is used to extract the “name” value and then line 12 overwrites the existing value of “Friend” with whatever input was passed.

HTML file loaded into the WebView with JavaScript Processing (hello.html)

What’s the problem?

This small program actually has numerous problems and poor design choices from a security perspective.

The biggest problem is that untrusted input is accepted and is not validated/sanitized before it is consumed. There is no “magic” inherent in the Intent handling that will protect you by default. While the application is expecting a name, there are no limits or controls on the input value in either the Java or JavaScript parts of the app. This means an attacker can craft a malicious payload in the [Name] field of a link like “example.com/hello/[Name]” URL, which can then be injected into the WebView. In the next few sections we will demo some exploits.

Before continuing with the exploit demo, here are some other concerns/comments:

  • There isn’t a clear need to rely on a WebView in the first place, it is better to limit the number of different programming languages and libraries you use in an app to reduce complexity
  • WebView is actually deprecated and there are better options out there from a security standpoint, but this is what people see in a lot of web tutorials. If it works, many developers won’t question it further 😦.
Screenshot showing that Android Studio tells you WebView is deprecated
  • Enabling JavaScript is risky, there are likely ways this particular functionality could have been accomplished without requiring JavaScript to be used in the first place
  • The mWebView.setWebChromeClient() function enables even further unnecessary functionality, such as allowing JavaScript alerts; you should only enable functionality you actually need, in order to minimize attack surface (see Line 29 in LoadDeepLink.java) (Learn more about this setting from this StackOverflow post)
  • In the actual HTML code loaded in the WebView (“hello.html”) on line 12 the [Name] value is set using nameSpan.innerHTML, since the expected value is just plain text, and not HTML, the *.textContent or *.innerText functions are likely more appropriate (Read more about these two methods on MDN)

Demos— Exploitation Walkthroughs

Using the application as intended (No attack)

Demo: App running normally with no attack

First, let’s run the application as originally intended:

When we first install and run the app we see the “main” activity screen which just shows “App Launched” this is just a placeholder for launching without the intent triggered by the URL handler.

We switch out of the App. Using the Google bar on the home screen we enter the following address:

“example.com/hello/John”

Android notices that our app has a registered handler and it prompts us to either open in our app or in another app. We select our app to handle the URL and we see “Hello, John” as expected.

Basic Notification Attack

The first attack will be a very simple proof of concept. We will trigger a Cross Site Scripting (XSS) attack by passing a malicious HTML string.

Passing some JavaScript inside <script /> tags will not work in this case. However, we can abuse the built-in onError attribute of HTML elements.

We simply inject an <img /> tag with an invalid src value, which will trigger the onerror condition where we defined our JavaScript attack.

Here is what the raw html code looks like, this is what we are setting at the [Name] value on the initial attack:

Raw code for Basic Notification Attack

In order to actually append this exploit code to the URL we must first URL-encode the content, which results in the following:

Attack code from above, in URL encoded format

Finally, we take the above URL-encoded exploit payload and append it to the base URL of “example.com/hello/” like this:

URL encoded exploit code appended to the URL

Let’s see what happens when we run this attack:

Demo: Basic Notification (JavaScript Alert) type attack from unvalidated JavaScript

Tricking Users into Visiting Links of Our Choosing Attack

Showing and alert pop-up is interesting for a simple PoC, but we wanted to show you how this one vulnerability could be used in other ways. Perhaps your first thought to fixing this application would be to simply disable JavaScript, however, the “hello.html” file would still allow arbitrary HTML to be added to the WebView.

For example, we could simply drop an <a /> link element and try to trick users into clicking on it. Here is the exploit payload we could use:

Exploit Code: A “name”=Victim, plus HTML code with a link

Again, we would need to first URL-encode it, but then we can pass it to our app the same way as we did in the previous example. See this in action below:

Video Demo showing how we can inject a link of our choosing onto a page. Would still require user to click the link.

Automated Redirect to Link of Our Choosing

However, since JavaScript is enabled, we can simply redirect the user to a malicious page under our control instead of simply hoping they will click our link. From the attacker standpoint, this means we can keep the payload small and easily update our malicious code on our own server whenever we want.

This code snippet uses the same onError trick we used in the alert pop-up, except this time we will automatically redirect the user to another page we control.

Again, this chunk of code must be URL-encoded and then can be put in the place of [Name] in the URL handled by our intent. See the video below to see this attack in action.

Note, nothing prevents the attacker from copying the HTML code from our app and spoofing the internal webpage. Since there is no URL bar at the top, the user has no way to know if they are on the real or fake website.

Demo showing automatic redirect to attacker chosen web page.

Demo — Wrap Up

There are a few key takeaways from this demo:

  • Always understand the classes and functionalities that you use in the mobile client app; understand all options and defaults… tl;dr READ THE DOCS!
  • Before using the first example code you find out there, or the easiest method, pick the best fit from performance, maintainability, and security perspectives. Ask for help from your security team
  • Always validate and sanitize input, whether supplied from a user, database, or anywhere else

Wrap Up

As you can see, even with a small application there is a lot to think about when it comes to securing your mobile app. Before coding on a new platform, take the time to read and understand all of the functionality. Many people move from web development to mobile app development and can start to make simple apps easily; however, there is a big difference between “getting it to work” and writing clean, maintainable, and secure code.

Invest in application security training and read the security documentation for your platform. Whenever you learn about a method or technique, spend some time researching security. You can start with a search like, “How to secure using feature X?”

Want to learn more about AppSec? Check out my other articles here on Medium. If you liked this article, don’t forget to hit the clap button 50x 👏 and share 🎁 with your friends on social media. Feel free to comment below with ideas and questions.

Read more by Eric H.Goldman:

OWASP Mobile Top 10 (2016) topics covered in this article: M1: Improper Platform Usage, M7: Client Code Quality

--

--