The Hidden Dangers of API Security in Mobile Apps

This article explores the security challenges in building SPAs and mobile apps, focusing on vulnerabilities like hardcoded API keys and interception risks in mobile banking apps. It offers insights and strategies to prevent these API security flaws, ensuring robust protection for users and data.

14 days ago   •   7 min read

By Stephen Rees-Carter
Table of contents

As a backend PHP developer and a security consultant, the only thing that terrifies me more than an SPA on top of a stateless API is a mobile app! 

Authentication (and authorization) in a traditional PHP app is relatively easy: give the user a secure cookie and store whatever information you need in the session. Each request includes the cookie, state is automatically across requests through the session, and nothing is exposed to the user.

Upgrading to an SPA on top of a stateless API adds an extra layer of complexity to the mix. Your SPA needs to collect user credentials, send those to the server and retrieve some form of token - and then send that with every future request to the API. With the right tools, it’s not that hard to get working, and it’s easy to shift a lot of the hard or sensitive work into the API. The mental separation between SPA and API is relatively easy - and because SPAs are javascript in the browser, you’re already considering the security implications. For more on API security challenges, see this article.

Mobile Apps on the other hand… they scare me.

To demonstrate why, let’s take a look at some “bank-grade security”!

“Bank-grade Security”?

When you think of banking websites and apps, you’re supposed to think “bank-grade security”, and set your expectations high. After all, banks need to protect their customers' money, right?

So naturally, when they build mobile apps, they’ll make them super secure… right? Check out some lessons learned from API security incidents here.

Well…

In 2021, Alissa Knight and Noname Security published research they did into mobile banking apps, which revealed some rather interesting findings. They reviewed 55 different banking apps, looking for common vulnerabilities and weaknesses in mobile apps, and the results were pretty shocking.

  • Almost all (54 out of 55) included hardcoded API keys in the mobile app.
  • All were vulnerable to Person-In-The-Middle (PITM) attacks.
  • All were vulnerable to Broken Object Level Authorization (BOLA) attacks.
  • All were vulnerable to other authentication vulnerabilities…

Let’s dig into each of these findings, and figure out where they went wrong.

Hardcoded API Keys

Traditional server-side applications store their API keys on the server, where an attacker is unable to access them. The user is typically authenticated and authorised through a session cookie, which remembers who they are and is stored within the browser, so there is no direct API or need for first-party keys, and any third-party API interactions is performed on the server, so the user never sees the keys.

SPAs typically feature some form of header token, which the server generates and shares with the API when the session is initiated, so nothing is hardcoded in the SPA in the browser. Even if these SPAs need to interact with third-party APIs, they’ll either proxy through their own API - to keep the keys protected on the server - or they’ll include special public keys which are designed to be used in the browser directly, and don’t pose a security risk.

But mobile apps pose a problem. The app isn’t running directly on the server, or from a recently downloaded javascript payload in the browser on a controlled domain. Mobile apps run independently on the devices they are installed on. 

This clear separation encourages mobile app devs to shift as much of the work as possible into the mobile app, which includes interacting with APIs - both their own and from third-parties. However, interacting with these APIs requires keys, and it’s really easy to see how a developer might think compiling an app makes the contents - and any keys it includes - unreadable.

There are tools, such as one aptly called “strings”, which extract all of the raw string values from a compiled file. All an attacker (or security researcher) needs to do is obtain the compiled app file (which is also easy), and then run these tools on the apps. It’ll spit out any API keys contained within the files.

As a side note, it’s not just banking apps which suffer from this. Kevin Watkins from security company Symantec released a report in September 2022, where they analysed over two-thousand mobile apps, on both Android and iOS, looking for hard-coded AWS credentials.

Of the apps analysed, over three quarters of the apps included valid private AWS access tokens, while almost half of those tokens gave access to private files in Amazon S3! They dug into it a lot further, so I’d suggest checking out the full report if you have the time, but the point I’m trying to make here is that it’s common for mobile apps to include hard coded API keys. Read more about avoiding hard-coded API keys here.

Intercepting Requests

The next finding in Alissa Knight research was the complete vulnerability to Person-In-The-Middle (PITM) attacks from all of the apps tested. This allowed her to intercept and decrypt the traffic between the banking apps and their APIs.

The risks here are twofold: 

Firstly, if an attacker can intercept and read API requests, they can use the app within a controlled environment and extract any keys and map out the API for the app. This can then be used to perform attacks and manipulate data, looking for vulnerabilities and weaknesses in the API.

Secondly, if someone uses these banking apps on an unprotected network, an attacker may be able to intercept the victim’s requests - reading sensitive information, such as their bank details, balance, etc. It may also allow the attacker to modify or forge requests - opening the door for the attacker to transfer money out of the victim’s bank account.

These risks highlight the need to properly secure API requests using multiple layers of protection. 

The first place to start is by requiring HTTPS on all API requests, with a valid certificate that matches the API hostname.  This ensures that the mobile app, and the device itself, will only trust legitimate HTTPS certificates, preventing opportunistic attacks on unsecured networks. There is still a risk of a malicious certificate being added to the device, but that requires a much more targeted and sophisticated attack.

These vulnerabilities often occur in mobile apps because it’s common for developers to disable certificate verification for dev and testing, to avoid needing to toggle hostnames and set up local HTTPS. However, in my opinion, the risks of disabling certificate verification far outweigh making the developers' lives a little bit easier! For an in-depth guide on API security, check this article.

The next layer is to look at some form of manipulation prevention on the API requests. This is commonly done using a checksum on the payload, which is verified before the API request is processed. Ideally, this should be performed on both sides - so both the client and the server verify the request is unmodified before processing it. This will prevent an attacker from intercepting a request and changing some numbers - such as redirecting payments from one bank account to another.

It is also important to include some record of time and expiry into API requests, to prevent Replay Attacks. These are attacks where an attacker records legitimate requests and then repeats them at a later point. This can be used to manipulate user data and can sometimes be used as part of a wider attack chain. By including a timestamp and having a limited expiry window, any requests made outside the window can be simply ignored. These values should be included within the checksum, to prevent them being manipulated too!

Broken Authentication & Authorization

These findings aren’t mobile app specific, but rather occur in all types of APIs, and basically mean that the API isn’t correctly checking who the user is and if they are allowed to do what they are attempting to do. In fact, it’s not even limited to APIs - it’s just a common vulnerability that occurs in any sort of application. Read more on API breaches and their consequences here.

If we check out the OWASP API Security Top 10 for 2023, here are all the risks which relate to this topic in some way:

  • API1:2023 - Broken Object Level Authorization
  • API2:2023 - Broken Authentication
  • API3:2023 - Broken Object Property Level Authorization
  • API5:2023 - Broken Function Level Authorization

Yep, 4 of the top 5 are different flavors of this issue.

And if we checkout the OWASP Web Application Security Top 10 for 2021:

  • A01:2021-Broken Access Control
  • A07:2021-Identification and Authentication Failures

Still got the top spot, plus #7.

This is clearly a common problem, given its prevalence in the OWASP’s Top 10 lists, and in my experience as a penetration tester, it comes down to developers just not considering authentication and authorization when writing their code. Learn more about API security tools that can help avoid these issues.

It’s so easy to get caught up in the business logic, what data needs to go in, and what data needs to go out, that it’s easy to overlook the question of: is this user actually allowed to access this data?

I think this also comes down to using decent frameworks and tooling. If you build your apps with a solid authentication and authorization system - something that ensures requests are only made by active users before your business logic kicks in, and provides a really easy way to check does this user have access to this resource, developers are more likely to consider it and use it when building out features.

Avoiding These Vulnerabilities

While the goal is for developers to not write insecure code, as a developer I know first hand that it’s easy to overlook subtle weaknesses and introduce vulnerabilities in code. As such, we really need to put protections and checks in place to help identify issues as they arise.

Firstly, as I mentioned above, building out solid authentication - OAuth 2.0 with OKCE (Proof Key for Code Exchange) is a good place to start for authenticating users, and implementing solid authorization checks within your API. Follow these up with automated tests that check permissions (this is something a lot of devs completely overlook!).

Secondly, use some automated tools like TruffleHog and run them against your codebase. Trufflehog is one of my favourite tools and it looks for committed API keys, secrets, and passwords, within your code. It’s fantastic at picking up things like AWS keys, so if your mobile app accidentally contains API keys, there is a good chance it’ll find them. If it’s hooked into your build and compile process, it’ll alert you for any secrets that find their way in before your code is deployed and released.

Thirdly, get some API monitoring, visibility, and auditing in place. If you’re aware of what’s going on with your APIs, the sort of requests your users are making, you’ll be better able to spot attacks and malicious behaviour and investigate - before someone abuses it! Treblle can help with this step. 🙂

Summary

Mobile apps present a unique security challenge, one you need to be aware of. Never forget that your users have full control over your mobile app, and thus your API. Everything the app has access to do, your users do as well. So make sure you lock it down so the mobile app has the same powers your users should.

💡
Start optimizing your API performance today with Treblle. Experience the benefits of real-time monitoring, comprehensive logging, and actionable insights. See how Treblle can enhance your API observability and help you maintain robust and reliable APIs!

Spread the word

Keep reading